diff --git a/card/standard.js b/card/standard.js index 850299e31..e979cc202 100644 --- a/card/standard.js +++ b/card/standard.js @@ -184,8 +184,8 @@ game.import('card',function(lib,game,ui,get,ai,_status){ } "step 3" if((!result||!result.bool||!result.result||result.result!='shaned')&&!event.unhurt){ - if (!event.directHit&&!event.directHit2&&lib.filter.cardEnabled(new lib.element.VCard('shan'), target, 'forceEnable')&& - target.hasCard(()=>true,'hs')&&get.damageEffect(target,player,target)<0) target.addGaintag(target.getCards('hs'),'sha_notshan'); + if (!event.directHit&&!event.directHit2&&lib.filter.cardEnabled(new lib.element.VCard({name:'shan'}), target, 'forceEnable')&& + target.countCards('hs')>0&&get.damageEffect(target,player,target)<0) target.addGaintag(target.getCards('hs'),'sha_notshan'); target.damage(get.nature(event.card)); event.result={bool:true} event.trigger('shaDamage'); diff --git a/card/yongjian.js b/card/yongjian.js index 18f63d18a..5e0a3e7e1 100644 --- a/card/yongjian.js +++ b/card/yongjian.js @@ -411,7 +411,7 @@ game.import('card',function(lib,game,ui,get,ai,_status){ equipSkill:true, forced:true, trigger:{target:'gift'}, - filter:(event,player)=>event.target!=player, + filter:(event,player)=>event.player!=player, logTarget:'player', content:()=>{ trigger.deniedGift.add(trigger.card); diff --git a/character/extra.js b/character/extra.js index 256698cac..2b712a371 100755 --- a/character/extra.js +++ b/character/extra.js @@ -155,8 +155,8 @@ game.import('character',function(lib,game,ui,get,ai,_status){ '虎:当你使用指定唯一目标的牌对目标角色造成伤害时,此伤害+1。', '鹿:①当你获得此效果时,你回复1点体力并弃置判定区的所有牌。②你不能成为延时锦囊牌的目标。', '熊:每回合限一次,当你受到伤害时,此伤害-1。', - '猿:出牌阶段开始时,你选择一名角色,随机获得其装备区里的一张牌。', - '鹤:出牌阶段开始时,你摸三张牌。', + '猿:当你获得此效果时,你选择一名其他角色,获得其装备区里的一张牌。', + '鹤:当你获得此效果时,你摸三张牌。', ], updateMark:function(player){ var wuqinxi=player.storage.wuling_wuqinxi; @@ -177,11 +177,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){ game.broadcastAll(function(player,curMark){ if(player.marks.wuling_wuqinxi) player.marks.wuling_wuqinxi.firstChild.innerHTML=curMark; },player,curMark); - if(curMark=='鹿'){ - player.logSkill('wuling_wuqinxi'); - player.recover(); - player.discard(player.getCards('j')).discarder=player; - } + var next=game.createEvent('wuling_change'); + next.player=player; + next.setContent('emptyEvent'); }, ai:{ order:7, @@ -214,7 +212,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, trigger:{ source:'damageBegin1', - player:['phaseZhunbeiBegin','damageBegin4','phaseUseBegin'], + player:['phaseZhunbeiBegin','damageBegin4','wuling_change'], }, filter:function(event,player,name){ const wuqinxi=player.storage.wuling_wuqinxi&&player.storage.wuling_wuqinxi[0]; @@ -228,9 +226,17 @@ game.import('character',function(lib,game,ui,get,ai,_status){ case 'damageBegin4': return wuqinxi=='熊'&&!player.hasSkill('wuling_xiong'); default: - if(wuqinxi=='鹤') return true; - if(wuqinxi!='猿') return false; - return game.hasPlayer(target=>target.countGainableCards(player,'e')); + switch(wuqinxi){ + case '鹿': + return player.isDamaged()||player.countCards('j'); + case '鹤': + return true; + case '猿': + return game.hasPlayer(target=>target!=playertarget.countGainableCards(player,'e')); + default: + return false; + } + break; } }, forced:true, @@ -256,31 +262,38 @@ game.import('character',function(lib,game,ui,get,ai,_status){ event.finish(); break; default: - if(wuqinxi=='鹤'){ - player.draw(3); - event.finish(); - } - else{ - player.chooseTarget('五禽戏:获得一名角色装备区里的一张装备牌',function(card,player,target){ - return target.countGainableCards(player,'e'); - }).set('ai',function(target){ - var player=_status.event.player; - var att=get.attitude(player,target),eff=0; - target.getCards('e',function(card){ - var val=get.value(card,target); - eff=Math.max(eff,-val*att); + switch(wuqinxi){ + case '鹿': + player.recover(); + player.discard(player.getCards('j')).discarder=player; + event.finish(); + break; + case '鹤': + player.draw(3); + event.finish(); + break; + case '猿': + player.chooseTarget('五禽戏:获得一名其他角色装备区里的一张装备牌',function(card,player,target){ + return target!=player&&target.countGainableCards(player,'e'); + }).set('ai',function(target){ + var player=_status.event.player; + var att=get.attitude(player,target),eff=0; + target.getCards('e',function(card){ + var val=get.value(card,target); + eff=Math.max(eff,-val*att); + }); + return eff; }); - return eff; - }); + break; } + break; } } 'step 1' if(result.bool){ var target=result.targets[0]; player.line(target,'green'); - var cards=target.getGainableCards(player,'e'); - player.gain(cards.randomGets(1),target,'give'); + player.gainPlayerCard(target,'e',true); } }, ai:{ @@ -7014,11 +7027,11 @@ game.import('character',function(lib,game,ui,get,ai,_status){ source:'damageSource' }, filter:function(event,player){ - if(get.attitude(_status.event.player,event.player)>=0) return false; if(player.storage.drlt_duorui.length) return false; return event.player.isIn()&&_status.currentPhase==player; }, check:function(event,player){ + if(get.attitude(_status.event.player,event.player)>=0) return false; if(player.hasEnabledSlot()&&!player.hasEnabledSlot(5)) return false; return true; }, @@ -8049,8 +8062,8 @@ game.import('character',function(lib,game,ui,get,ai,_status){ '
  • 虎:当你使用指定唯一目标的牌对目标角色造成伤害时,此伤害+1。'+ '
  • 鹿:①当你获得此效果时,你回复1点体力并弃置判定区的所有牌。②你不能成为延时锦囊牌的目标。'+ '
  • 熊:每回合限一次,当你受到伤害时,此伤害-1。'+ - '
  • 猿:出牌阶段开始时,你选择一名角色,随机获得其装备区里的一张牌。'+ - '
  • 鹤:出牌阶段开始时,你摸三张牌。', + '
  • 猿:当你获得此效果时,你选择一名其他角色,获得其装备区里的一张牌。'+ + '
  • 鹤:当你获得此效果时,你摸三张牌。', youyi:'游医', youyi_info:'①弃牌阶段结束时,你可以将所有于此阶段弃置的牌置入仁区。②出牌阶段限一次。你可以将仁区的所有牌置入弃牌堆,令所有角色各回复1点体力。', diff --git a/character/huicui.js b/character/huicui.js index 204981408..82d577a32 100644 --- a/character/huicui.js +++ b/character/huicui.js @@ -107,7 +107,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ sp_jishi:['dc_jiben','zhenghun','dc_sunhanhua','liuchongluojun'], sp_raoting:['dc_huanghao','dc_sunziliufang','dc_sunchen','dc_jiachong'], sp_yijun:['gongsundu','mengyou'], - sp_zhengyin:['yue_caiwenji','yue_zhoufei','yue_caiyong'], + sp_zhengyin:['yue_caiwenji','yue_zhoufei','yue_caiyong','yue_xiaoqiao'], } }, skill:{ @@ -658,7 +658,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ trigger:{global:'phaseEnd'}, forced:true, filter:function(event,player){ - return player.getHistory('useCard').length>player.getHp(); + return player.getHistory('useCard').length>player.getHp()||player.getHistory('gain').reduce((sum,evt)=>sum+evt.cards.length,0)>player.getHp(); }, content:function*(event,map){ const player=map.player; @@ -1094,9 +1094,8 @@ game.import('character',function(lib,game,ui,get,ai,_status){ trigger:{player:['gainAfter','loseAsyncAfter']}, forced:true, filter:(event,player)=>{ - // if(player==_status.currentPhase) return false; if(event.getParent('phaseDraw',true)) return false; - const evt=player.getHistory('gain')[0]; + const evt=player.getHistory('gain',i=>!i.getParent('phaseDraw',true))[0]; if(!evt) return false; if(event.name=='gain'){ if(evt!=event||event.getlx===false) return false; @@ -1109,8 +1108,8 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, content:function(){ var hs=player.getCards('h'),cards=trigger.getg(player); - var card=cards.filter(card=>hs.includes(card)).randomGet(); - player.addGaintag(card,'dclingkong_tag'); + cards=cards.filter(card=>hs.includes(card)); + player.addGaintag(cards,'dclingkong_tag'); game.delayx(); }, }, @@ -2254,7 +2253,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ logTarget:'player', content:function(){ var num=trigger.player.countMark('dcshengdu'); - player.draw(num); + player.draw(num*trigger.cards.length); trigger.player.removeMark('dcshengdu',num); }, } @@ -11093,6 +11092,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){ zhangchu:['zhangchu','jsrg_zhangchu'], xianglang:['xianglang','mb_xianglang'], chengui:['chengui','mb_chengui'], + liuyong:['liuyong','jsrg_liuyong'], + zhangxuan:['zhangxuan','jsrg_zhangxuan'], + gaoxiang:['gaoxiang','jsrg_gaoxiang'], }, translate:{ re_panfeng:'潘凤', @@ -11468,7 +11470,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ dcguangshi_info:'锁定技。准备阶段,若所有其他角色均有“信众”,你摸两张牌并失去1点体力。', dongwan:'董绾', dcshengdu:'生妒', - dcshengdu_info:'回合开始时,你可以选择一名其他角色,令其获得1枚“生妒”标记。有“生妒”标记的角色于摸牌阶段得到牌后,你摸X张牌,然后其移去所有“生妒”标记(X为其拥有的“生妒”标记数)。', + dcshengdu_info:'回合开始时,你可以选择一名其他角色,令其获得1枚“生妒”标记。有“生妒”标记的角色于摸牌阶段得到牌后,你摸X张牌,然后其移去所有“生妒”标记(X为摸牌数乘以其拥有的“生妒”标记数)。', dcjieling:'介绫', dcjieling_info:'出牌阶段每种花色限一次,你可以将两张花色不同的手牌当无距离限制且无任何次数限制的【杀】使用。然后若此【杀】:造成了伤害,所有目标角色失去1点体力;未造成伤害,所有目标角色依次获得1枚“生妒”标记。', yuanyin:'袁胤', @@ -11514,7 +11516,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ yue_zhoufei_prefix:'乐', dclingkong:'灵箜', dclingkong_tag:'箜篌', - dclingkong_info:'锁定技。①游戏开始时,你将所有手牌标记为“箜篌”。②你的“箜篌”牌不计入手牌上限。③当你于一回合内首次于摸牌阶段外得到牌后,系统随机将其中的一张牌标记为“箜篌”。', + dclingkong_info:'锁定技。①游戏开始时,你将所有手牌标记为“箜篌”。②你的“箜篌”牌不计入手牌上限。③当你于一回合内首次于摸牌阶段外得到牌后,你将这些牌标记为“箜篌”。', dcxianshu:'贤淑', dcxianshu_info:'出牌阶段,你可以将一张“箜篌”正面向上交给一名其他角色,然后你摸X张牌(X为你与其的体力值之差且至多为5)。若此牌为红色,且该角色的体力值不大于你,则其回复1点体力;若此牌为黑色,且该角色的体力值不小于你,则其失去1点体力。', dc_zhangmancheng:'张曼成', @@ -11531,7 +11533,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ dccaisi:'才思', dccaisi_info:'当你于回合内/回合外使用基本牌结算结束后,若你本回合以此法得到的牌数小于你的体力上限,你可以从牌堆/弃牌堆随机获得一张非基本牌,然后本回合下次发动此技能获得的牌数+1。', dczhuoli:'擢吏', - dczhuoli_info:'锁定技。一名角色的回合结束时,若你本回合使用的牌数大于体力值,你加1点体力上限(不能超过存活角色数),回复1点体力。', + dczhuoli_info:'锁定技。一名角色的回合结束时,若你本回合使用或获得的牌数大于体力值,你加1点体力上限(不能超过存活角色数),回复1点体力。', yue_caiyong:'乐蔡邕', yue_caiyong_prefix:'乐', dcjiaowei:'焦尾', @@ -11552,9 +11554,10 @@ game.import('character',function(lib,game,ui,get,ai,_status){ yue_xiaoqiao:'乐小乔', yue_xiaoqiao_prefix:'乐', dcqiqin:'绮琴', - dcqiqin_info:'锁定技。①游戏开始时,你将所有手牌标记为“乐”。②你的“乐”牌不计入手牌上限。③准备阶段,你获得弃牌堆中所有你标记过的“乐”牌。', + dcqiqin_tag:'琴', + dcqiqin_info:'锁定技。①游戏开始时,你将所有手牌标记为“琴”。②你的“琴”牌不计入手牌上限。③准备阶段,你获得弃牌堆中所有你标记过的“琴”牌。', dcweiwan:'媦婉', - dcweiwan_info:'出牌阶段限一次,你可以弃置一张“乐”并获得一名其他角色区域内花色与此牌不相同的牌各一张,若你获得了:一张牌,其失去1点体力;两张牌,本回合你对其使用牌无距离和次数限制;三张牌,本回合你不能对其使用牌。', + dcweiwan_info:'出牌阶段限一次,你可以弃置一张“琴”并随机获得一名其他角色区域内花色与此牌不相同的牌各一张,若你获得了:一张牌,其失去1点体力;两张牌,本回合你对其使用牌无距离和次数限制;三张牌,本回合你不能对其使用牌。', sp_baigei:'无双上将', sp_caizijiaren:'才子佳人', diff --git a/character/jsrg.js b/character/jsrg.js index 3b785c45c..bad9c601e 100644 --- a/character/jsrg.js +++ b/character/jsrg.js @@ -8,6 +8,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ jiangshanrugu_qi:['jsrg_liuhong','jsrg_hejin','jsrg_sunjian','jsrg_huangfusong','jsrg_xushao','jsrg_dongbai','jsrg_qiaoxuan','jsrg_yangbiao','jsrg_kongrong','jsrg_zhujun','jsrg_liubei','jsrg_wangyun','jsrg_liuyan','jsrg_caocao','jsrg_nanhualaoxian'], jiangshanrugu_cheng:['jsrg_sunce','jsrg_xuyou','jsrg_lvbu','jsrg_zhanghe','jsrg_zoushi','jsrg_guanyu','jsrg_chendeng','jsrg_zhenji','jsrg_zhangliao','jsrg_xugong','jsrg_chunyuqiong'], jiangshanrugu_zhuan:['jsrg_guojia','jsrg_zhangfei','jsrg_machao','jsrg_lougui','jsrg_zhangren','jsrg_huangzhong','jsrg_xiahourong','jsrg_sunshangxiang','jsrg_pangtong','jsrg_hansui','jsrg_zhangchu','jsrg_xiahouen','jsrg_fanjiangzhangda'], + jiangshanrugu_he:['jsrg_zhugeliang','jsrg_jiangwei','jsrg_luxun','jsrg_zhaoyun','jsrg_simayi','jsrg_guoxun','jsrg_sunlubansunluyu','jsrg_caofang','jsrg_sunjun','jsrg_liuyong','jsrg_weiwenzhugezhi','jsrg_zhangxuan','jsrg_gaoxiang','jsrg_guozhao'], }, }, character:{ @@ -53,14 +54,34 @@ game.import('character',function(lib,game,ui,get,ai,_status){ jsrg_zhangchu:['female','qun',3,['jsrghuozhong','jsrgrihui']], jsrg_xiahouen:['male','wei',4,['jsrghujian','jsrgshili'],['die_audio:tw_xiahouen']], jsrg_fanjiangzhangda:['male','wu',5,['jsrgfushan']], + //合 + jsrg_zhugeliang:['male','shu',3,['jsrgwentian','jsrgchushi','jsrgyinlve']], + jsrg_jiangwei:['male','shu',4,['jsrgjinfa','jsrgfumou','jsrgxuanfeng'],['border:wei']], + jsrg_luxun:['male','wu',3,['jsrgyoujin','jsrgdailao','jsrgzhubei']], + jsrg_zhaoyun:['male','shu',4,['jsrglonglin','jsrgzhendan']], + jsrg_simayi:['male','wei',4,['jsrgyingshi','jsrgtuigu']], + jsrg_guoxun:['male','wei',4,['jsrgeqian','jsrgfusha']], + jsrg_sunlubansunluyu:['female','wu',3,['jsrgdaimou','jsrgfangjie']], + jsrg_caofang:['male','wei','3/4',['jsrgzhaotu','jsrgjingju','jsrgweizhui']], + jsrg_sunjun:['male','wu',4,['jsrgyaoyan','jsrgbazheng']], + jsrg_liuyong:['male','shu',3,['jsrgdanxin','jsrgfengxiang']], + jsrg_weiwenzhugezhi:['male','wu',4,['jsrgfuhai']], + jsrg_zhangxuan:['female','wu',4,['jsrgtongli','jsrgshezang']], + jsrg_gaoxiang:['male','shu',4,['jsrgchiying']], + jsrg_guozhao:['female','wei',3,['jsrgpianchong','jsrgzunwei']], }, characterIntro:{ qiaoxuan:'桥玄(110年-184年6月6日),一作乔玄,字公祖。梁国睢阳县(今河南省商丘市睢阳区)人。东汉时期名臣。桥玄年轻时曾任睢阳县功曹,因坚持追究陈国相羊昌的恶行而闻名。后被举为孝廉,历任洛阳左尉、齐相及上谷、汉阳太守、司徒长史、将作大匠。汉桓帝末年,出任度辽将军,击败鲜卑、南匈奴、高句丽侵扰,保境安民。汉灵帝初年,迁任河南尹、少府、大鸿胪。建宁三年(170年),迁司空。次年,拜司徒。光和元年(178年),升任太尉。桥玄有感于国势日衰,于是称病请辞,改任太中大夫。光和七年(184年),桥玄去世,年七十五。桥玄性格刚强,不阿权贵,待人谦俭,尽管屡历高官,但不因为自己处在高位而有所私请。他为官清廉,去世后连下葬的钱都没有,被时人称为名臣。', lougui:'娄圭,字子伯,荆州南阳郡(治今河南南阳)人。曹魏时期著名谋士、将军,娄圭年轻时与曹操有交情,曾经随曹操平定冀州,南征刘表,击破马超,立有功劳,连曹操都感叹他的计谋。 后来曹操和他的儿子们一起出去游玩,娄圭当时也一起随行。因言语不当,被南郡(治今湖北荆州)人习授举报,曹操认为有意诽谤,遭杀害。在小说《三国演义》里,娄圭被设定为京兆人(今陕西西安),隐居终南山,道号“梦梅居士”。于第59回登场。', xiahourong:'夏侯荣(207年—219年) ,字幼权,名将夏侯渊之子。建安二十四年(219年)汉中之战,父亲夏侯渊战死后,夏侯荣不愿逃跑,随后拔剑冲入敌阵,战死。', + guoxun:'郭脩(?~253年),一作郭循,字孝先,凉州西平人,三国时期曹魏官员。原为曹魏中郎,被蜀汉将领姜维俘虏后降蜀汉,任左将军,后来刺杀了蜀汉大将军费祎。被曹魏追封为长乐乡侯,谥曰威侯。', + caofang:'曹芳(232年-274年),字兰卿,沛国谯县(今安徽省亳州市)人。三国时期曹魏第三位皇帝(239年1月22日-254年10月17日在位),疑为魏武帝曹操曾孙,任城威王曹彰之孙,任城王曹楷之子。太和六年(232年),生于任城王府。青龙三年(235年),选为魏明帝曹叡养子,册封齐王。景初三年(239年),立为皇太子,同日魏明帝曹叡病死,曹芳正式即位,由大将军曹爽和太尉司马懿共同辅政。正始十年,经历高平陵之变,曹爽倒台,政权落入司马氏手中。嘉平六年(254年),中书令李丰和光禄大夫张缉图谋废掉司马师,改立夏侯玄为大将军。司马师平定叛乱后,将曹芳废为齐王,拥戴高贵乡公曹髦继位。西晋建立后,册封邵陵县公。泰始十年(274年),曹芳病逝,终年四十三岁,谥号为厉。', + sunjun:'孙峻(219年-256年10月19日),字子远,扬州吴郡富春(今浙江省杭州市)人,昭义中郎将孙静曾孙,定武中郎将孙暠之孙,散骑侍郎孙恭之子。三国时期吴国宗室、权臣。孙峻从小弓马娴熟,胆量非凡。孙权晚年时,孙峻担任武卫都尉,掌握军权,然后又任侍中,开始涉足朝政。孙权临终前,孙峻接受遗诏同诸葛恪、滕胤共同辅佐朝政。此后,其身兼武卫将军,一直主持宫廷的值班、守卫等要害部门,并被封为都乡侯。孙峻生性喜好专断,容不下诸葛恪,于是与吴主孙亮密谋发动政变,在酒宴中设伏兵杀死诸葛恪。孙峻谋杀诸葛恪之后,升任丞相、大将军,督察内外一切军务,假节,晋封富春侯。此后,孙峻独揽朝政。孙峻在任职期间,滥施刑杀,淫乱宫女,和全公主孙鲁班私通。五凤元年(254年),吴侯孙英企图谋杀孙峻,后来事情被泄露,孙英自杀。时隔一年,吴国将军孙仪、张怡、林恂等人乘蜀国使节来访之机,共同谋划诛杀孙峻。后被孙峻发觉,孙仪自杀,林恂等被认为有罪诛死。太平元年(256年),孙峻梦见被诸葛恪所击,因惊悸恐惧发病而死,时年38岁。', + sunlubansunluyu:'孙鲁班,孙权之女。孙鲁班与孙权二子孙和不睦。孙权长子孙登死后,孙和被立为太子。孙鲁班向孙权进谗言废孙和太子之位,孙和被废后忧愤而死。
    孙鲁育,又名小虎,孙权与步练师之女。吴后期,孙鲁班诬陷孙鲁育参与谋反,于是孙峻杀害了孙鲁育。', jsrg_caocao:'初平元年二月,董卓徙天子都长安,焚洛阳宫室,众诸侯畏卓兵强,莫敢进。操怒斥众人:“为人臣而临此境,当举义兵以诛暴乱,大众已合,诸君何疑?此一战而天下定矣!”遂引兵汴水,遇卓将徐荣,大破之。操迎天子,攻吕布,伐袁术,安汉室,拜为征西将军。是时,袁绍兼四州之地,将攻许都。操欲扫清寰宇,兴复汉室,遂屯兵官渡。既克绍,操曰:“若天命在吾,吾为周文王矣。”', jsrg_sunce:'建安五年,操、绍相拒于官渡,孙策欲阴袭许昌,迎汉帝,遂密治兵,部署诸将。未发,会为许贡门客所刺,将计就计,尽托江东于权,诈死以待天时。八月,操、绍决战,孙策亲冒矢石,斩将刈旗,得扬、豫之地。曹操败走冀、青,刘备远遁荆、益。而后历时七年,孙策三分天下已有其二,帝于洛阳,建霸王未竟之功业。权表求吴王,封为仲帝,共治天下。', - jsrg_guojia:'初平元年二月,郭嘉拜见袁绍,闻曹操怒斥众诸侯,乃对曰:“董卓于汴水或有埋伏,慎之!”曹操未从,果败于徐荣。三月,曹操与郭嘉论天下事:“使孤成大业者,必此人也。”郭嘉从破袁绍,讨谭、尚,连战数克,计定辽东。时年三十八,征乌桓归途郭嘉因劳染疾,命悬之际竟意外饮下柳皮醋水而愈。建安十三年,曹操屯兵赤壁,郭嘉识破连环之计,议上中下三策,可胜刘备。尚未献策,曹操便决意采纳上策,“奉孝之才,足胜孤百倍,卿言上策,如何不取?”由此,赤壁战后曹操尽得天下。' + jsrg_guojia:'初平元年二月,郭嘉拜见袁绍,闻曹操怒斥众诸侯,乃对曰:“董卓于汴水或有埋伏,慎之!”曹操未从,果败于徐荣。三月,曹操与郭嘉论天下事:“使孤成大业者,必此人也。”郭嘉从破袁绍,讨谭、尚,连战数克,计定辽东。时年三十八,征乌桓归途郭嘉因劳染疾,命悬之际竟意外饮下柳皮醋水而愈。建安十三年,曹操屯兵赤壁,郭嘉识破连环之计,议上中下三策,可胜刘备。尚未献策,曹操便决意采纳上策,“奉孝之才,足胜孤百倍,卿言上策,如何不取?”由此,赤壁战后曹操尽得天下。', + jsrg_zhugeliang:'建兴六年春,汉丞相诸葛亮使赵云、邓芝为先锋,马谡为副将拒箕谷,牵制曹真主力。自率三十万大军攻祁山,三郡叛魏应亮,关中响震。曹叡命张郃拒亮,亮使定军山降将姜维与郃战于街亭,张郃久攻不下。后曹真强攻赵云军,赵云死战,坚守箕谷,马谡、邓芝当场战死忠勇殉国。……既克张郃,曹真溃逃,曹叡弃守长安,迁都邺城。十月,司马懿击退孙权,回援曹真。而后三年,丞相所到之处,无不望风而降,皆箪食壶浆,以迎汉军。尽收豫、徐、兖、并之地,建兴十年春,司马懿父子三人死于诸葛武侯火计,同年,孙权上表称臣,至此四海清平,大汉一统。而后诸葛亮荐蒋琬为丞相,姜维为大将军,自回隆中归隐,后主挽留再三,皆不受。魏延亦辞官相随,侍奉左右。后主时有不决之事,便往隆中拜访相父,均未得面,童子答曰外出云游,遗数锦囊,拆而视之,皆治国之良策也。', }, characterTitle:{ }, @@ -71,10 +92,12 @@ game.import('character',function(lib,game,ui,get,ai,_status){ allowDuplicate:true, blankCard:true, fullimage:true, + wuxieable:false, effect:function(){ 'step 0' - var card=event.cards[0]; - player.chooseUseTarget(card,`蓄谋:是否使用${get.translation(card)}?`,`请选择要使用的目标。若不使用此牌,则判定区内的所有“蓄谋”牌都将被置入弃牌堆。`); + var card=get.autoViewAs(event.cards[0]); + card.storage.xumou_jsrg=true; + player.chooseUseTarget(card,event.cards,`蓄谋:是否使用${get.translation(card)}?`,`请选择要使用的目标。若不使用此牌,则判定区内的所有“蓄谋”牌都将被置入弃牌堆。`); 'step 1' if(!result.bool){ var cards=player.getCards('j',card=>{ @@ -82,6 +105,10 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }); if(cards.length>0) player.loseToDiscardpile(cards); } + else{ + player.addTempSkill('xumou_jsrg_temp','phaseChange'); + player.markAuto('xumou_jsrg_temp',[event.cards[0].name]) + } }, }, ying:{ @@ -113,6 +140,1857 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, }, skill:{ + //江山如故·合 + //蓄谋临时禁用 + xumou_jsrg_temp:{ + charlotte:true, + onremove:true, + mod:{ + cardEnabled(card,player){ + if(!card.storage||!card.storage.xumou_jsrg) return; + if(player.getStorage('xumou_jsrg_temp').includes(get.name(card,false))) return false; + }, + }, + }, + //404诸葛亮 + jsrgwentian:{ + audio:2, + trigger:{ + player:['phaseZhunbeiBegin','phaseJudgeBegin','phaseDrawBegin','phaseUseBegin','phaseDiscardBegin','phaseJieshuBegin'], + }, + usable:1, + prompt2:'观看牌堆顶的五张牌,将其中一张交给其他角色,并将其余牌置于牌堆顶或牌堆底', + group:'jsrgwentian_viewas', + async content(event,trigger,player){ + const cards=get.cards(5); + game.cardsGotoOrdering(cards); + const {result}=await player.chooseButton([ + '问天:将一张牌交给一名其他角色', + cards + ],true); + if(result.bool){ + const {result:result2}=await player.chooseTarget(`将${get.translation(result.links)}交给一名其他角色`,lib.filter.notMe,true).set('ai',target=>{ + return get.attitude(get.player(),target); + }); + if(result2.bool){ + cards.removeArray(result.links); + const target=result2.targets[0]; + player.line(target,'green'); + await target.gain(result.links,'gain2').set('giver',player); + } + } + const next=player.chooseToMove(); + next.set('list',[ + ['牌堆顶',cards.filterInD()], + ['牌堆底'], + ]); + next.set('prompt','问天:点击将牌移动到牌堆顶或牌堆底'); + next.processAI=list=>{ + const cards=list[0][1],player=_status.event.player; + const top=[]; + const judges=player.getCards('j'); + let stopped=false; + if(!player.hasWuxie()){ + for(let i=0;ijudge(b)-judge(a)); + if(judge(cards[0])<0){ + stopped=true;break; + } + else{ + top.unshift(cards.shift()); + } + } + } + let bottom; + if(!stopped){ + cards.sort((a,b)=>get.value(b,player)-get.value(a,player)); + while(cards.length){ + if(get.value(cards[0],player)<=5) break; + top.unshift(cards.shift()); + } + } + bottom=cards; + return [top,bottom]; + } + const {result:{moved}}=await next; + const top=moved[0]; + const bottom=moved[1]; + top.reverse(); + game.cardsGotoPile( + top.concat(bottom), + ['top_cards',top], + (event,card)=>{ + if(event.top_cards.includes(card)) return ui.cardPile.firstChild; + return null; + } + ); + player.popup(get.cnNumber(top.length)+'上'+get.cnNumber(bottom.length)+'下'); + game.log(player,'将'+get.cnNumber(top.length)+'张牌置于牌堆顶'); + game.asyncDelayx(); + }, + subSkill:{ + viewas:{ + audio:'jsrgwentian', + enable:'chooseToUse', + filter:function(event,player){ + for(const name of ['wuxie','huogong']){ + if(event.filterCard({name},player,event)) return true; + } + return false; + }, + hiddenCard:function(player,name){ + if(player.isTempBanned('jsrgwentian')) return false; + return name=='wuxie'; + }, + viewAs:function(cards,player){ + const event=get.event(),filter=event._backup.filterCard; + for(const name of ['wuxie','huogong']){ + if(filter({name},player,event)) return {name}; + } + return null; + }, + filterCard:()=>false, + selectCard:-1, + prompt:function(){ + const player=get.player(); + const event=get.event(),filter=event._backup.filterCard; + let str='将牌堆顶的牌当【'; + for(const name of ['wuxie','huogong']){ + if(filter({name},player,event)){ + str+=get.translation(name); break; + } + } + str+='】使用'; + return str; + }, + precontent(){ + player.logSkill('jsrgwentian'); + const cards=get.cards(); + event.result.cards=cards; + delete event.result.skill; + game.cardsGotoOrdering(cards); + const color=event.result.card.name=='wuxie'?'black':'red'; + if(get.color(cards,false)!=color){ + player.tempBanSkill('jsrgwentian','roundStart'); + } + } + } + } + }, + jsrgchushi:{ + audio:2, + enable:'phaseUse', + usable:1, + filter(event,player){ + const zhu=get.zhu(player); + if(!zhu||!zhu.isZhu2()) return false; + return !player.isZhu2(); + }, + async content(event,trigger,player){ + player.chooseToDebate(game.filterPlayer(current=>{ + return current==player||current.isZhu2(); + })).set('callback',async event=>{ + const result=event.debateResult; + if(result.bool&&result.opinion){ + const {opinion,targets}=result; + targets.sortBySeat(); + if(opinion=='red'){ + do{ + for(const current of targets){ + await current.draw(); + } + } + while(targets.map(current=>{ + return current.countCards('h'); + }).reduce((p,c)=>{ + return p+c; + },0)<7); + } + else{ + player.addMark('jsrgchushi_add',1,false); + player.addTempSkill('jsrgchushi_add','roundStart'); + } + } + }) + }, + subSkill:{ + add:{ + audio:'jsrgchushi', + trigger:{source:'damageBegin1'}, + filter:function(event){ + return event.hasNature('linked'); + }, + forced:true, + charlotte:true, + onremove:true, + async content(_,trigger,player){ + trigger.num+=player.countMark('jsrgchushi_add'); + }, + ai:{ + damageBonus:true, + skillTagFilter:function(player,tag,arg){ + if(tag==='damageBonus') return arg&&arg.card&&game.hasNature(arg.card,'linked'); + } + }, + intro:{ + content:'造成的属性伤害+#', + } + } + } + }, + jsrgyinlve:{ + audio:2, + trigger:{ + global:'damageBegin4', + }, + filter:function(event,player){ + return event.player.isIn()&&['fire','thunder'].some(n=>!player.hasSkill(`jsrgyinlve_${n}`)&&event.hasNature(n)); + }, + check:function(event,player){ + if(get.damageEffect(event.player,event.source,player,get.natureList(event.nature))<-5) return true; + return false; + }, + logTarget:'player', + async content(event,trigger,player){ + trigger.cancel(); + const natures=['fire','thunder']; + let index; + if(natures.every(n=>!player.hasSkill(`jsrgyinlve_${n}`)&&trigger.hasNature(n))){ + const {result}=await player.chooseControl(['摸牌阶段','弃牌阶段']).set('prompt','请选择要新回合内仅有的阶段'); + index=result.index; + } + else index=[0,1].find(i=>!player.hasSkill(`jsrgyinlve_${natures[i]}`)&&trigger.hasNature(natures[i])); + player.addTempSkill(`jsrgyinlve_${natures[index]}`,'roundStart'); + player.insertPhase().set('phaseList',[['phaseDraw','phaseDiscard'][index]]); + }, + subSkill:{ + fire:{charlotte:true}, + thunder:{charlotte:true}, + } + }, + //姜维 + jsrgjinfa:{ + audio:2, + enable:'phaseUse', + usable:1, + filterCard:true, + position:'h', + discard:false, + lose:false, + delay:false, + check:function(){ + return 1+Math.random(); + }, + async content(event,trigger,player){ + await player.showCards(event.cards); + player.chooseToDebate(game.filterPlayer(current=>{ + return current.maxHp<=player.maxHp; + })).set('callback',async (event)=>{ + const result=event.debateResult; + if(result.bool&&result.opinion){ + const {cards:fixedCards}=event.getParent('jsrgjinfa'); + const color=get.color(fixedCards); + const {opinion,targets}=result; + if(opinion==color){ + const {result}=await player.chooseTarget('是否令至多两名参与议事的角色将手牌摸至体力上限?',[1,2],(card,player,target)=>{ + return get.event('targets').includes(target); + }).set('targets',targets).set('ai',target=>{ + const player=get.player(); + const att=get.attitude(player,target); + if(att<=0) return -1; + return att*Math.sqrt(Math.max(0.1,target.maxHp-target.countCards('h'))); + }); + if(result.bool){ + const targets=result.targets; + targets.sortBySeat(); + player.line(targets,'green'); + for(const current of targets){ + if(current.countCards('h'){ + if(!get.event('change')) return 'cancel2'; + const controls=get.event('controls'); + const groups=['wei','shu'].filter(g=>controls.includes(g)); + if(groups.length) return groups.randomGet(); + return controls.randomGet(); + }).set('change',['wei','shu'].includes(player.group)?(Math.random()<0.5):true); + if(control!='cancel2'){ + player.popup(control+'2',get.groupnature(control,'raw')); + player.changeGroup(control); + } + } + }); + }, + ai:{ + order:function(item,player){ + if(player.countCards('h')==1) return 10; + return 1; + }, + result:{ + player:1, + }, + } + }, + jsrgfumou:{ + audio:2, + trigger:{global:'chooseToDebateAfter'}, + groupSkill:true, + forced:true, + locked:false, + filter:function(event,player){ + if(player.group!='wei') return false; + if(!event.targets.includes(player)) return false; + if(event.red.some(i=>i[0]==player)) return event.black.length; + if(event.black.some(i=>i[0]==player)) return event.red.length; + return false; + }, + async content(event,trigger,player){ + const targets=[]; + if(trigger.red.some(i=>i[0]==player)) targets.addArray(trigger.black.map(i=>i[0])); + if(trigger.black.some(i=>i[0]==player)) targets.addArray(trigger.red.map(i=>i[0])); + player.line(targets,'thunder'); + targets.forEach(target=>{ + target.addTempSkill('jsrgfumou_forbid'); + target.markAuto('jsrgfumou_forbid',['red','black'].filter(color=>{ + return trigger[color].some(i=>i[0]==target); + })) + }); + game.broadcastAll(targets=>{ + lib.skill.jsrgfumou_backup.targets=targets; + },targets); + const next=player.chooseToUse(); + next.set('openskilldialog',`是否将一张【影】当【出其不意】对一名与你意见不同的角色使用?`); + next.set('norestore',true); + next.set('_backupevent','jsrgfumou_backup'); + next.set('custom',{ + add:{}, + replace:{window:function(){}} + }); + next.backup('jsrgfumou_backup'); + }, + subSkill:{ + backup:{ + filterCard:function(card){ + return get.itemtype(card)=='card'&&get.name(card)=='ying'; + }, + viewAs:{ + name:'chuqibuyi', + }, + selectCard:1, + position:'hs', + log:false, + filterTarget:function(card,player,target){ + const targets=lib.skill.jsrgfumou_backup.targets; + if(!targets.includes(target)||ui.selected.targets.containsSome(targets)) return false; + return lib.filter.targetEnabled.apply(this,arguments); + }, + ai1:function(card){ + return 6-get.value(card); + }, + precontent:function(){ + delete event.result.skill; + }, + }, + forbid:{ + charlotte:true, + onremove:true, + mod:{ + cardEnabled:function(card,player){ + if(player.getStorage('jsrgfumou_forbid').includes(get.color(card))) return false; + }, + cardRespondable:function(card,player){ + if(player.getStorage('jsrgfumou_forbid').includes(get.color(card))) return false; + }, + cardSavable:function(card,player){ + if(player.getStorage('jsrgfumou_forbid').includes(get.color(card))) return false; + }, + }, + mark:true, + intro:{ + content:'本回合不能使用或打出$牌', + }, + } + } + }, + jsrgxuanfeng:{ + audio:2, + enable:'chooseToUse', + filterCard:{name:'ying'}, + position:'hs', + groupSkill:true, + locked:false, + viewAs:{ + name:'sha', + nature:'stab', + storage:{jsrgxuanfeng:true}, + }, + viewAsFilter(player){ + if(player.group!='shu') return false; + if(!player.countCards('hs','ying')) return false; + }, + prompt:'将一张【影】当无距离和次数限制的刺【杀】使用', + check(card){ + const val=get.value(card); + return 5-val; + }, + mod:{ + targetInRange:function(card,player,target){ + if(card.storage&&card.storage.jsrgxuanfeng) return true; + }, + cardUsable:function(card){ + if(card.storage&&card.storage.jsrgxuanfeng) return Infinity; + } + }, + ai:{ + order:2, + } + }, + //陆逊 + jsrgyoujin:{ + audio:2, + trigger:{player:'phaseUseBegin'}, + filter(event,player){ + return game.hasPlayer(current=>{ + return player.canCompare(current); + }); + }, + direct:true, + async content(event,trigger,player){ + const {result}=await player.chooseTarget(get.prompt2('jsrgyoujin'),(card,player,target)=>{ + return player.canCompare(target); + }).set('ai',target=>{ + if(!get.event('goon')) return 0; + return -get.attitude(get.player(),target); + }).set('goon',player.countCards('hs',['shan','caochuan'])||player.getHp()>=3); + if(!result.bool) return; + const {targets}=result,target=targets[0]; + player.logSkill('jsrgyoujin',target); + const {result:result2}=await player.chooseToCompare(target).set('small',true); + player.addTempSkill('jsrgyoujin_forbid'); + player.markAuto('jsrgyoujin_forbid',[result2.num1]); + target.addTempSkill('jsrgyoujin_forbid'); + target.markAuto('jsrgyoujin_forbid',[result2.num2]); + if(!result2.tie){ + const targets=[target,player]; + if(result2.bool) targets.reverse(); + const sha=new lib.element.VCard({name:'sha'}); + if(targets[0].canUse(sha,targets[1],false)){ + targets[0].useCard(sha,targets[1],false); + } + } + }, + subSkill:{ + forbid:{ + charlotte:true, + onremove:true, + mod:{ + cardEnabled2:function(card,player){ + if(get.itemtype(card)=='card'&&player.getStorage('jsrgyoujin_forbid').some(num=>num>get.number(card))) return false; + }, + }, + mark:true, + intro:{ + content:'本回合不能使用或打出点数小于$的手牌', + }, + } + } + }, + jsrgdailao:{ + audio:2, + enable:'phaseUse', + filter(event,player){ + return !player.hasCard(card=>{ + return player.hasUseTarget(card); + }); + }, + async content(event,trigger,player){ + await player.showHandcards(); + await player.draw(2); + const evt=event.getParent('phase'); + if(evt){ + game.resetSkills(); + _status.event=evt; + _status.event.finish(); + _status.event.untrigger(true); + } + }, + ai:{ + order:0.0001, + result:{player:1}, + } + }, + jsrgzhubei:{ + audio:2, + trigger:{source:'damageBegin1'}, + forced:true, + init(player){ + player.addSkill('jsrgzhubei_record'); + }, + filter(event,player){ + return event.player.hasHistory('damage',evt=>{ + return evt.source==player; + }); + }, + logTarget:'player', + async content(event,trigger,player){ + trigger.num++; + }, + subSkill:{ + record:{ + trigger:{ + global:['loseAfter','equipAfter','addJudgeAfter','gainAfter','loseAsyncAfter','addToExpansionAfter'], + }, + charlotte:true, + silent:true, + filter(event,player){ + return game.hasPlayer(current=>{ + if(current.countCards('h')) return false; + const evt=event.getl(current); + return evt&&evt.hs&&evt.hs.length; + }); + }, + async content(event,trigger,player){ + game.countPlayer(current=>{ + if(current.countCards('h')) return false; + const evt=trigger.getl(current); + if(evt&&evt.hs&&evt.hs.length) current.addTempSkill('jsrgzhubei_lost'); + }); + }, + }, + lost:{charlotte:true}, + }, + mod:{ + cardUsableTarget(card,player,target){ + if(target.hasSkill('jsrgzhubei_lost')) return true; + }, + }, + }, + //赵云 + jsrglonglin:{ + audio:2, + trigger:{ + global:'useCardToPlayered', + }, + usable:1, + filter(event,player){ + if(event.player==player) return false; + if(event.card.name!='sha') return false; + return event.isFirstTarget&&event.player.isPhaseUsing(); + }, + direct:true, + async content(event,trigger,player){ + const juedou=new lib.element.VCard({name:'juedou',storage:{jsrglonglin:true}}); + const {result}=await player.chooseToDiscard(get.prompt2('jsrglonglin'),'he').set('ai',card=>{ + if(get.event('goon')) return 5-get.value(card); + return 0; + }).set('goon',(trigger.player.canUse(juedou,player)?Math.max(0,get.effect(player,juedou,trigger.player,trigger.player)):0)+trigger.targets.map(target=>{ + return get.effect(target,trigger.card,trigger.player,player); + }).reduce((p,c)=>{ + return p+c; + },0)<-4).set('logSkill',['jsrglonglin',trigger.player]); + if(result.bool){ + trigger.excluded.addArray(trigger.targets); + game.asyncDelayx(); + if(trigger.player.canUse(juedou,player)){ + const {result}=await trigger.player.chooseBool(`是否视为对${get.translation(player)}使用一张【决斗】?`).set('choice',get.effect(player,juedou,trigger.player,trigger.player)>=0); + if(result.bool){ + player.addTempSkill('jsrglonglin_source'); + trigger.player.useCard(juedou,player); + } + } + } + }, + subSkill:{ + source:{ + trigger:{source:'damageSource'}, + charlotte:true, + forced:true, + popup:false, + filter(event,player){ + return event.card&&event.card.storage&&event.card.storage.jsrglonglin; + }, + async content(event,trigger,player){ + player.line(trigger.player); + trigger.player.addTempSkill('jsrglonglin_forbid'); + } + }, + forbid:{ + mod:{ + cardEnabled:function(card,player){ + if(!card.cards) return; + if(card.cards.some(cardx=>get.position(cardx)=='h')) return false; + }, + cardSavable:function(card,player){ + if(!card.cards) return; + if(card.cards.some(cardx=>get.position(cardx)=='h')) return false; + }, + }, + charlotte:true, + mark:true, + intro:{ + content:'不能使用手牌', + }, + }, + }, + }, + jsrgzhendan:{ + audio:2, + trigger:{ + player:'damageEnd', + global:'roundStart', + }, + filter(event,player){ + let count=0; + let roundCount=1+(event.name!='damage'); + const curLen=player.actionHistory.length; + for(let i=curLen-1;i>=0;i--){ + if(roundCount==1&&game.hasPlayer(current=>{ + const history=current.actionHistory[i]; + if(!history.isMe||history.isSkipped) return false; + return true; + })){ + count++; + } + if(player.actionHistory[i].isRound) roundCount--; + if(roundCount<=0) break; + } + if(!player.storage.jsrgzhendan_mark&&count>0) return true; + return false; + }, + forced:true, + locked:false, + group:'jsrgzhendan_viewas', + async content(event,trigger,player){ + let count=0; + let roundCount=1+(trigger.name!='damage'); + const curLen=player.actionHistory.length; + for(let i=curLen-1;i>=0;i--){ + if(roundCount==1&&game.hasPlayer(current=>{ + const history=current.actionHistory[i]; + if(!history.isMe||history.isSkipped) return false; + return true; + })){ + count++; + } + if(player.actionHistory[i].isRound) roundCount--; + if(roundCount<=0) break; + } + count=Math.min(5,count); + await player.draw(count); + if(trigger.name=='damage'){ + player.tempBanSkill('jsrgzhendan','roundStart'); + player.storage.jsrgzhendan_mark=true; + player.when({global:'roundStart'}).assign({ + lastDo:true, + }).then(()=>{ + delete player.storage.jsrgzhendan_mark; + }); + } + }, + subSkill:{ + viewas:{ + audio:'jsrgzhendan', + enable:['chooseToUse','chooseToRespond'], + filter(event,player){ + if(event.type=='wuxie') return false; + if(!_status.connectMode&&!player.countCards('hs',card=>{ + return get.type2(card)!='basic'; + })) return false; + return get.inpileVCardList(info=>{ + if(info[0]!='basic') return false; + return event.filterCard({name:info[2],nature:info[3]},player,event); + }).length; + }, + chooseButton:{ + dialog(event,player){ + const vcards=get.inpileVCardList(info=>{ + if(info[0]!='basic') return false; + return event.filterCard({name:info[2],nature:info[3]},player,event); + }); + return ui.create.dialog('镇胆',[vcards,'vcard']); + }, + check(button){ + if(get.event().getParent().type!='phase') return 1; + return get.player().getUseValue({name:button.link[2],nature:button.link[3]}); + }, + backup(links,player){ + return { + audio:'jsrgzhendan', + popname:true, + viewAs:{name:links[0][2],nature:links[0][3]}, + filterCard(card,player){ + return get.type2(card)!='basic'; + }, + selectCard:1, + position:'hs', + } + }, + prompt(links,player){ + return '将一张非基本手牌当'+(get.translation(links[0][3])||'')+get.translation(links[0][2])+'使用或打出'; + } + }, + hiddenCard(player,name){ + return get.type(name)=='basic'&&player.countCards('hs')>0; + }, + ai:{ + respondSha:true, + respondShan:true, + skillTagFilter(player){ + return player.countCards('hs')>0; + }, + order:0.5, + result:{ + player(player){ + if(get.event().dying){ + return get.attitude(player,get.event().dying); + } + return 1; + }, + }, + }, + }, + viewas_backup:{}, + } + }, + //司马懿 + jsrgyingshi:{ + audio:2, + trigger:{player:'turnOverAfter'}, + async content(event,trigger,player){ + const number=(game.dead.length>2)?5:3; + const cards=get.bottomCards(number); + game.cardsGotoOrdering(cards); + const next=player.chooseToMove(); + next.set('list',[ + ['牌堆顶'], + ['牌堆底',cards.reverse()], + ]); + next.set('prompt','鹰眎:点击将牌移动到牌堆顶或牌堆底'); + next.processAI=list=>{ + const cards=list[1][1],player=_status.event.player; + const top=[]; + const judges=player.getCards('j'); + let stopped=false; + if(!player.hasWuxie()){ + for(let i=0;ijudge(b)-judge(a)); + if(judge(cards[0])<0){ + stopped=true;break; + } + else{ + top.unshift(cards.shift()); + } + } + } + let bottom; + if(!stopped){ + cards.sort((a,b)=>get.value(b,player)-get.value(a,player)); + while(cards.length){ + if(get.value(cards[0],player)<=5) break; + top.unshift(cards.shift()); + } + } + bottom=cards; + return [top,bottom]; + } + const {result:{moved}}=await next; + const top=moved[0]; + const bottom=moved[1]; + top.reverse(); + game.cardsGotoPile( + top.concat(bottom), + ['top_cards',top], + (event,card)=>{ + if(event.top_cards.includes(card)) return ui.cardPile.firstChild; + return null; + } + ); + player.popup(get.cnNumber(top.length)+'上'+get.cnNumber(bottom.length)+'下'); + game.log(player,'将'+get.cnNumber(top.length)+'张牌置于牌堆顶'); + game.asyncDelayx(); + }, + }, + jsrgtuigu:{ + audio:2, + trigger:{player:'phaseBegin'}, + prompt2(event,player){ + const num=Math.floor(game.countPlayer()/2); + return `你翻面,令你本回合的手牌上限+${num},摸${get.cnNumber(num)}张牌,视为使用一张【解甲归田】(目标角色不能使用这些牌直到其下回合结束)。`; + }, + group:['jsrgtuigu_insert','jsrgtuigu_recover'], + async content(event,trigger,player){ + await player.turnOver(); + const num=Math.floor(game.countPlayer()/2); + player.addTempSkill('jsrgtuigu_handcard'); + player.addMark('jsrgtuigu_handcard',num,false); + await player.draw(num); + const jiejia=new lib.element.VCard({name:'jiejia',storage:{jsrgtuigu:true}}); + if(player.hasUseTarget(jiejia)){ + player.addTempSkill('jsrgtuigu_block'); + player.chooseUseTarget(jiejia,true); + } + }, + subSkill:{ + insert:{ + audio:'jsrgtuigu', + trigger:{global:'roundStart'}, + filter(event,player){ + const curLen=player.actionHistory.length; + if(curLen<=2) return false; + for(let i=curLen-2;i>=0;i--){ + const history=player.actionHistory[i]; + if(history.isMe&&!history.isSkipped) return false; + if(history.isRound) break; + } + return true; + }, + forced:true, + locked:false, + async content(event,trigger,player){ + const evt=trigger; + player.insertPhase(); + if(evt.player!=player&&!evt._finished){ + evt.finish(); + evt._triggered=5; + evt.player.insertPhase(); + } + }, + }, + recover:{ + audio:'jsrgtuigu', + trigger:{ + player:'loseAfter', + global:['gainAfter','equipAfter','addJudgeAfter','loseAsyncAfter','addToExpansionAfter'], + }, + filter(event,player){ + if(player.isHealthy()) return false; + const evt=event.getl(player); + return evt&&evt.es&&evt.es.length>0; + }, + forced:true, + locked:false, + async content(event,trigger,player){ + player.recover(); + } + }, + handcard:{ + markimage:'image/card/handcard.png', + intro:{ + content(storage,player){ + return '手牌上限+'+storage; + } + }, + charlotte:true, + mod:{ + maxHandcard(player,num){ + return num+player.countMark('jsrgtuigu_handcard'); + } + }, + }, + block:{ + trigger:{global:'gainAfter'}, + filter(event,player){ + if(event.getParent().name!='jiejia') return false; + const card=event.getParent(2).card; + if(card&&card.storage&&card.storage.jsrgtuigu) return true; + return false; + }, + charlotte:true, + forced:true, + silent:true, + content(){ + trigger.player.addGaintag(trigger.cards,'jsrgtuigu'); + trigger.player.addTempSkill('jsrgtuigu_blocked',{player:'phaseAfter'}); + } + }, + blocked:{ + mod:{ + cardEnabled2(card){ + if(get.itemtype(card)=='card'&&card.hasGaintag('jsrgtuigu')) return false; + }, + }, + charlotte:true, + forced:true, + popup:false, + onremove(player){ + player.removeGaintag('jsrgtuigu'); + }, + }, + } + }, + //郭循 + jsrgeqian:{ + audio:2, + trigger:{player:'useCardToPlayered'}, + filter(event,player){ + if(!event.isFirstTarget||event.targets.length!=1||event.target==player) return false; + if(event.card.name=='sha') return true; + return event.getParent(3).name=='xumou_jsrg'; + }, + prompt2(event,player){ + return `令${get.translation(event.card)}不计入次数限制,且你获得${get.translation(event.target)}一张牌,然后其可以令你本回合至其的距离+2`; + }, + group:'jsrgeqian_prepare', + async content(event,trigger,player){ + if(trigger.addCount!==false){ + trigger.addCount=false; + var stat=player.getStat().card,name=trigger.card.name; + if(typeof stat[name]=='number') stat[name]--; + } + await player.gainPlayerCard(trigger.target,'he',true); + const {result:{bool}}=await trigger.target.chooseBool(`是否令${get.translation(player)}至你的距离于本回合内+2?`).set('ai',()=>true); + if(bool){ + player.addTempSkill('jsrgeqian_distance'); + if(!player.storage.jsrgeqian_distance) player.storage.jsrgeqian_distance={}; + const id=trigger.target.playerid; + if(typeof player.storage.jsrgeqian_distance[id]!='number') player.storage.jsrgeqian_distance[id]=0; + player.storage.jsrgeqian_distance[id]+=2; + player.markSkill('jsrgeqian_distance'); + } + }, + subSkill:{ + prepare:{ + audio:'jsrgeqian', + trigger:{player:'phaseJieshuBegin'}, + filter(event,player){ + return player.countCards('h'); + }, + direct:true, + async content(event,trigger,player){ + while(true){ + const {result:{bool,cards}}=await player.chooseCard(get.prompt('jsrgeqian'),'你可以蓄谋任意次').set('ai',card=>{ + const player=get.player(); + if(player.hasValueTarget(card)) return player.getUseValue(card); + return 0; + }); + if(!bool) break; + player.addJudge({name:'xumou_jsrg'},cards); + } + }, + }, + distance:{ + onremove:true, + charlotte:true, + mod:{ + globalFrom(player,target,distance){ + if(!player.storage.jsrgeqian_distance) return; + const dis=player.storage.jsrgeqian_distance[target.playerid]; + if(typeof dis=='number') return distance+dis; + }, + }, + intro:{ + content(storage,player){ + if(!storage) return; + const map=(_status.connectMode?lib.playerOL:game.playerMap); + let str=`你本回合:`; + for(const id in storage){ + str+='
  • 至'+get.translation(map[id])+'的距离+'+storage[id]; + } + return str; + } + } + }, + } + }, + jsrgfusha:{ + audio:2, + enable:'phaseUse', + limited:true, + skillAnimation:true, + animationColor:'fire', + filter(event,player){ + return game.countPlayer(current=>{ + return player.inRange(current); + })==1; + }, + filterTarget(card,player,target){ + return player.inRange(target); + }, + selectTarget:-1, + async content(event,trigger,player){ + player.awakenSkill('jsrgfusha'); + event.target.damage(Math.min(game.countPlayer(),player.getAttackRange())); + }, + ai:{ + order:1, + result:{ + target:-2, + }, + }, + }, + //大小虎 + jsrgdaimou:{ + audio:2, + trigger:{ + global:'useCardToPlayer', + }, + filter(event,player){ + if(event.card.name!='sha') return false; + if(event.target!=player) return !player.hasSkill('jsrgdaimou_other'); + return !player.hasSkill('jsrgdaimou_me')&&player.hasCard(card=>{ + return (card.viewAs||card.name)=='xumou_jsrg'&&lib.filter.cardDiscardable(card,player,'jsrgdaimou'); + },'j'); + }, + direct:true, + async content(event,trigger,player){ + if(trigger.target==player){ + player.logSkill('jsrgdaimou'); + player.addTempSkill('jsrgdaimou_me'); + const {result:{bool,links}}=await player.chooseButton([ + '殆谋:请弃置区域里的一张蓄谋牌', + player.getCards('j',card=>{ + return (card.viewAs||card.name)=='xumou_jsrg'; + }) + ],true).set('filterButton',button=>{ + return lib.filter.cardDiscardable(button.link,get.player(),'jsrgdaimou'); + }).set('ai',button=>{ + const player=get.player(); + return 1/Math.max(0.01,player.getUseValue(button.link)); + }); + if(bool){ + player.discard(links); + } + } + else{ + const {result:{bool}}=await player.chooseBool(get.prompt('jsrgdaimou'),'你可以用牌堆顶的牌蓄谋').set('ai',()=>true); + if(bool){ + player.logSkill('jsrgdaimou'); + player.addTempSkill('jsrgdaimou_other'); + player.addJudge({name:'xumou_jsrg'},get.cards()); + } + } + }, + subSkill:{ + me:{charlotte:true}, + other:{charlotte:true}, + }, + }, + jsrgfangjie:{ + audio:2, + trigger:{player:'phaseZhunbeiBegin'}, + direct:true, + async content(event,trigger,player){ + if(!player.hasCard(card=>{ + return (card.viewAs||card.name)=='xumou_jsrg'; + },'j')){ + player.logSkill('jsrgfangjie'); + await player.recover(); + await player.draw(); + } + else{ + const {result:{bool,links}}=await player.chooseButton([ + '是否弃置区域里的任意张蓄谋牌并失去〖芳洁〗?', + player.getCards('j',card=>{ + return (card.viewAs||card.name)=='xumou_jsrg'; + }) + ],[1,Infinity]).set('filterButton',button=>{ + return lib.filter.cardDiscardable(button.link,get.player(),'jsrgdaimou'); + }).set('ai',()=>0); + if(bool){ + player.logSkill('jsrgfangjie'); + await player.discard(links); + player.removeSkillLog('jsrgfangjie'); + } + } + }, + }, + //曹芳 + jsrgzhaotu:{ + audio:2, + enable:'chooseToUse', + viewAs:{name:'lebu'}, + position:'hes', + viewAsFilter(player){ + return player.countCards('hes'); + }, + filterCard(card,player){ + return get.color(card)=='red'&&get.type2(card)!='trick'; + }, + onuse(result,player){ + player.tempBanSkill('jsrgzhaotu',null,false); + result.targets[0].insertPhase(); + result.targets[0].addTempSkill('jsrgzhaotu_handcard',{player:'phaseAfter'}); + result.targets[0].addMark('jsrgzhaotu_handcard',2,false); + }, + subSkill:{ + handcard:{ + intro:{ + content(storage,player){ + return '手牌上限-'+storage; + } + }, + charlotte:true, + mod:{ + maxHandcard(player,num){ + return num-player.countMark('jsrgzhaotu_handcard'); + } + }, + }, + }, + ai:{ + order:5, + result:{ + target(player,target){ + if(player.hasSkill('jsrgjingju')||player.hasZhuSkill('jsrgweizhui')) return get.attitude(player,target); + return -1; + }, + }, + }, + }, + jsrgjingju:{ + audio:2, + enable:'chooseToUse', + filter(event,player){ + if(event.type=='wuxie'||event.jsrgjingju) return false; + if(!player.canMoveCard(null,false,game.filterPlayer(i=>i!=player),player,card=>{ + return get.position(card)=='j'; + })) return false; + return get.inpileVCardList(info=>{ + if(info[0]!='basic') return false; + return event.filterCard({name:info[2],nature:info[3]},player,event); + }).length; + }, + chooseButton:{ + dialog:function(event,player){ + const vcards=get.inpileVCardList(info=>{ + if(info[0]!='basic') return false; + return event.filterCard({name:info[2],nature:info[3]},player,event); + }); + return ui.create.dialog('惊惧',[vcards,'vcard'],'hidden'); + }, + check:function(button){ + if(get.event().getParent().type!='phase') return 1; + return get.player().getUseValue({name:button.link[2],nature:button.link[3]}); + }, + backup:function(links,player){ + return { + filterCard:()=>false, + viewAs:{ + name:links[0][2], + nature:links[0][3], + isCard:true, + }, + selectCard:-1, + precontent(){ + 'step 0' + player.moveCard(`惊惧:将其他角色判定区里的牌移动至你的判定区`,game.filterPlayer(i=>i!=player),player,card=>{ + return get.position(card)=='j'; + }).set('logSkill','jsrgjingju'); + 'step 1' + if(result.bool){ + delete event.result.skill; + } + else{ + event.getParent().jsrgjingju=true; + event.getParent().goto(0); + delete event.getParent().openskilldialog; + event.finish(); + } + 'step 2' + game.delayx(); + }, + } + }, + prompt:function(links,player){ + return '选择'+get.translation(links[0][3]||'')+'【'+get.translation(links[0][2])+'】的目标'; + } + }, + ai:{ + order:function(){ + const player=get.player(),event=_status.event; + if(player.canMoveCard(null,false,game.filterPlayer(),player,card=>{ + return get.position(card)=='j'; + })){ + if(event.type=='dying'){ + if(event.filterCard({name:'tao'},player,event)){ + return 0.5; + } + } + else{ + if(event.filterCard({name:'tao'},player,event)||event.filterCard({name:'shan'},player,event)){ + return 4; + } + if(event.filterCard({name:'sha'},player,event)){ + return 2.9; + } + } + } + return 0; + }, + save:true, + respondSha:true, + respondShan:true, + skillTagFilter:function(player,tag,arg){ + return player.canMoveCard(null,false,game.filterPlayer(),player,card=>{ + return get.position(card)=='j'; + }) + }, + result:{ + player:function(player){ + if(get.event().type=='dying'){ + return get.attitude(player,get.event().dying); + } + return 1; + } + } + } + }, + jsrgweizhui:{ + audio:2, + trigger:{global:'phaseJieshuBegin'}, + zhuSkill:true, + direct:true, + filter(event,player){ + return player!=event.player&&event.player.group=='wei'&&event.player.isIn()&&player.hasZhuSkill('jsrgweizhui',event.player); + }, + async content(event,trigger,player){ + const {result:{bool,cards}}=await trigger.player.chooseCard(`是否响应${get.translation(player)}的主公技【危坠】?`,'将一张黑色手牌当【过河拆桥】对其使用',(card,player)=>{ + if(get.color(card)!='black') return false; + return player.canUse(get.autoViewAs({name:'guohe'},[card]),get.event('target')); + }).set('target',player).set('ai',card=>{ + if(get.effect(get.event('target'),get.autoViewAs({name:'guohe'},[card]),player)<=0) return 0; + return 6-get.value(card); + }); + if(bool){ + trigger.player.logSkill('jsrgweizhui',player); + trigger.player.useCard(get.autoViewAs({name:'guohe'},cards),cards,player); + } + }, + }, + //孙峻 + jsrgyaoyan:{ + audio:2, + trigger:{player:'phaseZhunbeiBegin'}, + prompt:'是否发动【邀宴】?', + logTarget:()=>game.filterPlayer(), + async content(event,trigger,player){ + const targets=game.filterPlayer(); + const toDebateList=[]; + while(targets.length){ + const current=targets.shift(); + const {result:{bool}}=await current.chooseBool(`是否响应${get.translation(player)}的【邀宴】,于回合结束参与议事?`).set('ai',()=>Math.random()<0.5); + if(bool){ + toDebateList.add(current); + current.popup('同意','wood'); + game.log(current,'#g同意','参加',player,'的议事'); + } + else{ + current.popup('拒绝','fire'); + game.log(current,'#r拒绝','参加',player,'的议事'); + } + } + if(toDebateList.length){ + player.addTempSkill('jsrgyaoyan_hold'); + player.markAuto('jsrgyaoyan_hold',toDebateList); + } + }, + subSkill:{ + hold:{ + trigger:{player:'phaseEnd'}, + charlotte:true, + forced:true, + popup:false, + onremove:true, + filter(event,player){ + return player.getStorage('jsrgyaoyan_hold').some(i=>i.isIn()); + }, + async content(event,trigger,player){ + player.chooseToDebate(player.getStorage('jsrgyaoyan_hold').filter(i=>i.isIn())).set('callback',async event=>{ + const {bool,opinion,targets}=event.debateResult; + if(bool&&opinion){ + if(opinion=='red'){ + const notDebated=game.filterPlayer().removeArray(targets); + if(notDebated.length){ + const {result}=await player.chooseTarget('获得任意名未议事的角色的各一张手牌',[1,Infinity],true,(card,player,target)=>{ + return get.event('targets').includes(target)&&target.countGainableCards(player,'h'); + }).set('targets',notDebated).set('ai',target=>{ + const player=get.player(); + const att=get.attitude(player,target); + return -att; + }); + if(result.bool){ + const targets=result.targets; + targets.sortBySeat(); + player.line(targets,'green'); + for(const current of targets){ + await player.gainPlayerCard(current,'h',true); + } + } + } + } + else{ + const {result:{bool,targets:targets2}}=await player.chooseTarget('是否对一名议事的角色造成2点伤害?',(card,player,target)=>{ + return get.event('targets').includes(target); + }).set('targets',targets).set('ai',target=>{ + const player=get.player(); + const eff=get.damageEffect(target,player,player); + return eff; + }); + if(bool){ + player.line(targets2[0]); + targets2[0].damage(2); + } + } + } + }); + }, + } + } + }, + jsrgbazheng:{ + audio:2, + trigger:{global:'debateShowOpinion'}, + filter(event,player){ + if(!event.targets.includes(player)) return false; + const damagedPlayers=player.getHistory('sourceDamage').map(evt=>evt.player).toUniqued(); + let dissent; + const colors=['red','black']; + for(const color of colors){ + if(event[color].some(i=>i[0]==player)){ + dissent=colors.find(i=>i!=color); + break; + } + } + return event[dissent].some(i=>damagedPlayers.includes(i[0])); + }, + forced:true, + locked:false, + direct:true, + async content(event,trigger,player){ + let myOpinion,dissent; + const colors=['red','black']; + for(const color of colors){ + if(trigger[color].some(i=>i[0]==player)){ + myOpinion=color; + dissent=colors.find(i=>i!=color); + break; + } + } + const damagedPlayers=player.getHistory('sourceDamage').map(evt=>evt.player).toUniqued(); + let dissident=[]; + for(let i=0;iget.suit(card)=='heart')){ + const owners=trigger.cards.filter((card=>get.suit(card)=='heart')).map(card=>get.owner(card)).toUniqued(); + for(const owner of owners){ + if(owner&&owner.isIn()) await owner.recover(); + } + } + if(trigger.player==player) return; + player.addTempSkill('jsrgdanxin_distance'); + if(!player.storage.jsrgdanxin_distance) player.storage.jsrgdanxin_distance={}; + const id=targets[0].playerid; + if(typeof player.storage.jsrgdanxin_distance[id]!='number') player.storage.jsrgdanxin_distance[id]=0; + player.storage.jsrgdanxin_distance[id]++; + player.markSkill('jsrgdanxin_distance'); + }, + }, + distance:{ + onremove:true, + charlotte:true, + mod:{ + globalFrom(player,target,distance){ + if(!player.storage.jsrgdanxin_distance) return; + const dis=player.storage.jsrgdanxin_distance[target.playerid]; + if(typeof dis=='number') return distance+dis; + }, + }, + intro:{ + content(storage,player){ + if(!storage) return; + const map=(_status.connectMode?lib.playerOL:game.playerMap); + let str=`你本回合:`; + for(const id in storage){ + str+='
  • 至'+get.translation(map[id])+'的距离+'+storage[id]; + } + return str; + } + } + }, + } + }, + jsrgfengxiang:{ + audio:'fengxiang', + trigger:{player:'damageEnd'}, + forced:true, + direct:true, + filter(event,player){ + return game.hasPlayer(current=>{ + return current.countCards('e'); + }) + }, + async content(event,trigger,player){ + const {result:{bool,targets}}=await player.chooseTarget('封乡:与一名其他角色交换装备区里的所有牌',(card,player,target)=>{ + return target.countCards('e')+player.countCards('e')>0&&player!=target; + },true).set('ai',target=>{ + const player=get.player(); + const att=get.attitude(player,target); + let delta=get.value(target.getCards('e'),player)-get.value(player.getCards('e'),player); + if(att>0){ + if(delta<0) delta+=att/3; + } + else{ + if(delta<0) delta-=att/3; + } + return delta; + }); + if(bool){ + player.logSkill('jsrgfengxiang',targets[0]); + const num=player.countCards('e'); + await player.swapEquip(targets[0]); + const delta=num-player.countCards('e'); + if(delta>0) player.draw(delta); + } + }, + }, + jsrgfuhai:{ + audio:'xinfu_fuhai', + enable:'phaseUse', + usable:1, + filter(event,player){ + return game.hasPlayer(current=>{ + return current.countCards('h')&¤t!=player; + }) + }, + filterTarget(card,player,target){ + return target.countCards('h')&&target!=player; + }, + selectTarget:-1, + multitarget:true, + multiline:true, + async content(event,trigger,player){ + const targets=event.targets.sortBySeat(); + const next=player.chooseCardOL(targets,'请展示一张手牌',true).set('ai',card=>{ + return -get.value(card); + }).set('aiCard',target=>{ + const hs=target.getCards('h'); + return {bool:true,cards:[hs.randomGet()]}; + }); + next._args.remove('glow_result'); + const {result}=await next; + const cards=[]; + const videoId=lib.status.videoId++; + for(let i=0;i{ + var dialog=ui.create.dialog(get.translation(player)+'发动了【浮海】',cards); + dialog.videoId=id; + const getName=(target)=>{ + if(target._tempTranslate) return target._tempTranslate; + var name=target.name; + if(lib.translate[name+'_ab']) return lib.translate[name+'_ab']; + return get.translation(name); + } + for(let i=0;iincrease){ + increase=number; + flag=true; + } + else increase=Infinity; + if(numberget.event('choice')).set('choice',clock>anticlock?0:1) + player.draw(index==0?clock:anticlock); + }, + ai:{ + order:8, + result:{player:1}, + } + }, + //张嫙 + jsrgtongli:{ + audio:'tongli', + trigger:{player:'useCardToPlayered'}, + filter(event,player){ + if(!event.isFirstTarget) return false; + const type=get.type(event.card); + if(type!='basic'&&type!='trick') return false; + const hs=player.getCards('h'); + if(!hs.length) return false; + const evt=event.getParent('phaseUse'); + if(!evt||evt.player!=player) return false; + const num1=player.getHistory('useCard',evtx=>{ + return evtx.getParent('phaseUse')==evt; + }).length; + if(hs.length{ + let str='奢葬'; + if(player==game.me&&!_status.auto){ + str+=':获得任意张花色各不相同的牌'; + } + const dialog=ui.create.dialog(str,cards); + dialog.videoId=id; + },player,videoId,cards); + const time=get.utc(); + game.addVideo('showCards',player,['奢葬',get.cardsInfo(event.cards)]); + game.addVideo('delay',null,2); + const list=[]; + for(const i of cards) list.add(get.suit(i,false)); + const next=player.chooseButton([1,list.length]); + next.set('dialog',event.videoId); + next.set('filterButton',function(button){ + for(var i=0;i0){ + await game.asyncDelay(0,time2); + } + game.broadcastAll('closeDialog',videoId); + player.gain(result.links,'gain2'); + } + }, + }, + jsrgchiying:{ + audio:'dcchiying', + enable:'phaseUse', + usable:1, + filterTarget:true, + async content(event,trigger,player){ + const target=event.target; + const targets=game.filterPlayer(current=>target.inRange(current)&¤t!=player).sortBySeat(player); + if(!targets.length) return; + while(targets.length){ + const current=targets.shift(); + if(current.countCards('he')) await current.chooseToDiscard('驰应:请弃置一张牌','he',true); + } + let cards=[]; + game.getGlobalHistory('cardMove',evt=>{ + if(evt.getParent(3)==event){ + cards.addArray(evt.cards.filter(card=>get.type(card)=='basic')); + } + }); + if(cards.length<=target.getHp()){ + cards=cards.filterInD('d'); + if(cards.length) target.gain(cards,'gain2'); + } + }, + ai:{ + order:6, + result:{ + target(player,target){ + const targets=game.filterPlayer(current=>target.inRange(current)&¤t!=player); + let eff=0; + for(const targetx of targets){ + let effx=get.effect(targetx,{name:'guohe_copy2'},player,target); + if(get.attitude(player,targetx)<0) effx/=2; + eff+=effx; + } + return eff*(get.attitude(player,target)<=0?0.75:1); + } + } + } + }, + //郭照 + jsrgpianchong:{ + audio:'pianchong', + trigger:{global:'phaseJieshuBegin'}, + filter(event,player){ + return player.getHistory('lose').length; + }, + frequent:true, + async content(event,trigger,player){ + player.judge().set('callback',()=>{ + const red=[],black=[]; + game.getGlobalHistory('cardMove',evt=>{ + if(evt.name!='cardsDiscard'){ + if(evt.name!='lose'||evt.position!=ui.discardPile) return false; + } + const cards=evt.cards.filter(card=>get.position(card,true)=='d'); + red.addArray(cards.filter(i=>get.color(i,false)=='red')); + black.addArray(cards.filter(i=>get.color(i,false)=='black')); + }); + if(event.judgeResult.color=='red'&&red.length){ + player.draw(red.length); + } + else if(event.judgeResult.color=='black'&&black.length){ + player.draw(black.length); + } + }) + }, + }, + jsrgzunwei:{ + audio:'zunwei', + enable:'phaseUse', + usable:1, + filter(event,player){ + const storage=player.getStorage('jsrgzunwei'); + return storage.length<3&&game.hasPlayer(current=>{ + return player.isDamaged()&¤t.getHp()>player.getHp()&&!storage.includes(2)|| + current.countCards('h')>player.countCards('h')&&!storage.includes(0)|| + current.countCards('e')>player.countCards('e')&&!storage.includes(1); + }); + }, + chooseButton:{ + dialog(event,player){ + const list=[ + '选择手牌数大于你的一名角色', + '选择装备数大于你的一名角色', + '选择体力值大于你的一名角色', + ]; + const choiceList=ui.create.dialog('尊位:请选择一项','forcebutton','hidden'); + choiceList.add([list.map((item,i)=>{ + if(player.getStorage('jsrgzunwei').includes(i)) item=`${item}`; + return [i,item]; + }),'textbutton']) + return choiceList; + }, + filter(button){ + const player=get.player(); + if(player.getStorage('jsrgzunwei').includes(button.link)) return false; + if(button.link==2){ + if(!player.isDamaged()) return false; + return game.hasPlayer(current=>{ + return current.getHp()>player.getHp(); + }); + } + if(button.link==0){ + return game.hasPlayer(current=>{ + return current.countCards('h')>player.countCards('h'); + }); + } + if(button.link==1){ + return game.hasPlayer(current=>{ + return current.countCards('e')>player.countCards('e'); + }); + } + }, + backup(links){ + const next=get.copy(lib.skill.jsrgzunwei.backups[links[0]]); + next.audio='zunwei'; + next.filterCard=function(){return false}; + next.selectCard=-1; + return next; + }, + check(button){ + const player=get.player(); + switch(button.link){ + case 2:{ + const target=game.findPlayer(function(current){ + return current.isMaxHp(); + }); + return (Math.min(target.hp,player.maxHp)-player.hp)*2; + } + case 0:{ + const target=game.findPlayer(function(current){ + return current.isMaxHandcard(); + }); + return Math.min(5,target.countCards('h')-player.countCards('h'))*0.8; + } + case 1:{ + const target=game.findPlayer(function(current){ + return current.isMaxEquip(); + }); + return (target.countCards('e')-player.countCards('e'))*1.4; + } + } + }, + prompt(links){ + return [ + '选择一名手牌数大于你的其他角色,将手牌数摸至与其相同(至多摸五张)', + '选择一名装备区内牌数大于你的其他角色,将其装备区里的牌移至你的装备区,直到你装备数不小于其', + '选择一名体力值大于你的其他角色,将体力值回复至与其相同', + ][links[0]]; + }, + }, + backups:[ + { + filterTarget(card,player,target){ + return target.countCards('h')>player.countCards('h'); + }, + async content(event,trigger,player){ + player.draw(Math.min(5,event.target.countCards('h')-player.countCards('h'))); + if(!player.storage.jsrgzunwei) player.storage.jsrgzunwei=[]; + player.storage.jsrgzunwei.add(0); + }, + ai:{ + order:10, + result:{ + player:function(player,target){ + return Math.min(5,target.countCards('h')-player.countCards('h')); + }, + }, + }, + }, + { + filterTarget(card,player,target){ + return target.countCards('e')>player.countCards('e'); + }, + async content(event,trigger,player){ + if(!player.storage.jsrgzunwei) player.storage.jsrgzunwei=[]; + player.storage.jsrgzunwei.add(1); + const target=event.target; + do{ + if(!target.countCards('e',card=>{ + return player.canEquip(card); + })) break; + const {result:{bool,links}}=await player.chooseButton([ + `尊位:将${get.translation(target)}的一张装备牌移至你的区域内`, + target.getCards('e') + ],true).set('filterButton',button=>{ + return get.player().canEquip(button.link); + }).set('ai',get.buttonValue); + if(bool){ + target.$give(links[0],player,false); + await player.equip(links[0]); + } + } + while(player.countCards('e')player.hp; + }, + async content(event,trigger,player){ + player.recover(event.target.hp-player.hp); + if(!player.storage.jsrgzunwei) player.storage.jsrgzunwei=[]; + player.storage.jsrgzunwei.add(2); + }, + ai:{ + order:10, + result:{ + player:function(player,target){ + return (Math.min(target.hp,player.maxHp)-player.hp); + }, + }, + }, + }, + ], + ai:{ + order:10, + result:{ + player:1, + }, + }, + subSkill:{ + backup:{}, + } + }, //江山如故·转 //404郭嘉 jsrgqingzi:{ @@ -935,7 +2813,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ ai1:function(card){ var player=get.player(); var maxVal=5.5; - if(get.name(card,false)=='ying'&&player.hasSkill('jsrgchuaxin')) maxVal-=3; + if(get.name(card,false)=='ying'&&player.hasSkill('jsrgchuanxin')) maxVal-=3; return maxVal-get.value(card); }, precontent:function(){ @@ -6329,6 +8207,94 @@ game.import('character',function(lib,game,ui,get,ai,_status){ jsrg_fanjiangzhangda_prefix:'转', jsrgfushan:'负山', jsrgfushan_info:'出牌阶段开始时,所有其他角色可以依次交给你一张牌并令你此阶段使用【杀】的次数上限+1。此阶段结束时,若你使用【杀】的次数未达到上限且此阶段以此法交给你牌的角色均存活,你失去2点体力,否则你将手牌摸至体力上限。', + jsrg_zhugeliang:'梦诸葛亮', + jsrg_zhugeliang_prefix:'梦', + jsrgwentian:'问天', + jsrgwentian_info:'①你可以将牌堆顶的牌当【无懈可击】/【火攻】使用,若此牌不为黑色/红色,〖问天〗于本轮失效。②每回合限一次。你的一个阶段开始时,你可以观看牌堆顶的五张牌,然后将其中一张牌交给一名其他角色,将其余牌以任意顺序置于牌堆顶或牌堆底。', + jsrgchushi:'出师', + jsrgchushi_info:'出牌阶段限一次。若你不为主公,你可以与主公议事。若结果为:红色,你与其各摸一张牌,若你与其手牌数之和小于7,重复此流程;黑色,当你于本轮内造成属性伤害时,此伤害+1。', + jsrgyinlve:'隐略', + jsrgyinlve_info:'每轮各限一次。当一名角色受到火焰/雷电伤害时,你可以防止此伤害,然后于当前回合结束后执行一个只有摸牌/弃牌阶段的回合。', + jsrg_jiangwei:'合姜维', + jsrg_jiangwei_prefix:'合', + jsrgjinfa:'矜伐', + jsrgjinfa_info:'出牌阶段限一次。你可以展示一张手牌,然后令所有体力上限不大于你的角色议事。若结果与此牌颜色:相同,你令其中至多两名角色将手牌摸至体力上限;不同,你获得两张【影】。然后若没有其他角色与你意见相同,你可以变更势力。', + jsrgfumou:'复谋', + jsrgfumou_info:'魏势力技。当你议事结算结束后,与你意见不同的角色本回合不能使用或打出与其意见颜色相同的牌,你可以将一张【影】当【出其不意】对一名与你意见不同的角色使用。', + jsrgxuanfeng:'选锋', + jsrgxuanfeng_info:'蜀势力技。你可以将一张【影】当无距离和次数限制的刺【杀】使用。', + jsrg_luxun:'合陆逊', + jsrg_luxun_prefix:'合', + jsrgyoujin:'诱进', + jsrgyoujin_info:'出牌阶段开始时,你可以与一名角色拼点,你与其本回合不能使用或打出点数小于自己拼点牌的手牌,且赢的角色视为对没赢的角色使用一张【杀】。', + jsrgdailao:'待劳', + jsrgdailao_info:'出牌阶段,若你没有可以使用的手牌,你可以展示所有手牌并摸两张牌,然后结束此回合。', + jsrgzhubei:'逐北', + jsrgzhubei_info:'锁定技。①当你对本回合受到过伤害的角色造成伤害时,此伤害+1。②你对本回合失去过最后手牌的角色使用牌无次数限制。', + jsrg_zhaoyun:'合赵云', + jsrg_zhaoyun_prefix:'合', + jsrglonglin:'龙临', + jsrglonglin_info:'其他角色于其出牌阶段内首次使用【杀】指定第一个目标后,你可以弃置一张牌令此【杀】无效,然后其可以视为对你使用一张【决斗】,你以此法造成伤害后,其本阶段不能再使用手牌。', + jsrgzhendan:'镇胆', + jsrgzhendan_info:'①你可以将一张非基本手牌当任意基本牌使用或打出。②当你受到伤害后,你摸X张牌并令该技能本轮失效(X为本轮所有角色执行过的回合数且至多为5)。③一轮游戏开始时,若上一轮该技能未因〖镇胆②〗失效过,你摸Y张牌(Y为上一轮所有角色执行过的回合数且至多为5)。', + jsrg_simayi:'合司马懿', + jsrg_simayi_prefix:'合', + jsrgyingshi:'鹰眎', + jsrgyingshi_info:'当你翻面时,你可以观看牌堆底的三张牌(若死亡角色数大于2则改为五张),然后将其中任意数量的牌以任意顺序置于牌堆顶,其余以任意顺序置于牌堆底。', + jsrgtuigu:'蜕骨', + jsrgtuigu_info:'①回合开始时,你可以翻面并令你本回合的手牌上限+X,然后摸X张牌并视为使用一张【解甲归田】(X为存活角色数的一半,向下取整),目标角色不能使用以此法得到的牌直到其回合结束。②一轮游戏开始时,若你上一轮未执行过回合,你获得一个额外的回合。③当你失去装备牌里的牌后,你回复1点体力。', + jsrg_guoxun:'合郭循', + jsrg_guoxun_prefix:'合', + jsrgeqian:'遏前', + jsrgeqian_info:'①结束阶段,你可以蓄谋任意次。②当你使用【杀】或蓄谋牌指定其他角色为唯一目标后,你可以令此牌不计入次数限制并获得目标一张牌,然后其可以令你本回合至其的距离+2。', + jsrgfusha:'伏杀', + jsrgfusha_info:'限定技。出牌阶段,若你的攻击范围内仅有一名角色,你可以对其造成X点伤害(X为你的攻击范围,至多为游戏人数)。', + jsrg_sunlubansunluyu:'合孙鲁班孙鲁育', + jsrg_sunlubansunluyu_prefix:'合', + jsrgdaimou:'殆谋', + jsrgdaimou_info:'每回合各限一次。当一名角色使用【杀】指定其他角色/你为目标时,你可以用牌堆顶的牌蓄谋/你须弃置你区域里的一张蓄谋牌。', + jsrgfangjie:'芳洁', + jsrgfangjie_info:'准备阶段,若你没有蓄谋牌,你回复1点体力并摸一张牌,否则你可以弃置你区域里的任意张蓄谋牌并失去〖芳洁〗。', + jsrg_caofang:'合曹芳', + jsrg_caofang_prefix:'合', + jsrgzhaotu:'诏图', + jsrgzhaotu_info:'每轮限一次。你可以将一张红色非锦囊牌当【乐不思蜀】使用,然后当前回合结束后,目标执行一个手牌上限-2的额外回合。', + jsrgjingju:'惊惧', + jsrgjingju_info:'当你需要使用任意一种基本牌时,你可以将其他角色判定区里的一张牌移动至你的判定区,视为你使用之。', + jsrgweizhui:'危坠', + jsrgweizhui_info:'主公技。其他魏势力角色的结束阶段,其可以将一张黑色手牌当【过河拆桥】对你使用。', + jsrg_sunjun:'合孙峻', + jsrg_sunjun_prefix:'合', + jsrgyaoyan:'邀宴', + jsrgyaoyan_info:'准备阶段,你可以令所有角色依次选择是否于回合结束时议事,若议事结果为:红色,你获得任意名未议事的角色各一张手牌;黑色,你可以对一名议事的角色造成2点伤害。', + jsrgbazheng:'霸政', + jsrgbazheng_info:'当你参与的议事展示意见时,本回合受到过你伤害的角色意见视为与你相同。', + jsrg_liuyong:'合刘永', + jsrg_liuyong_prefix:'合', + jsrgdanxin:'丹心', + jsrgdanxin_info:'你可以将一张牌当【推心置腹】使用,你展示以此法交出与得到的牌,以此法得到♥牌的角色回复1点体力,然后你至目标角色的距离+1直到回合结束。', + jsrgfengxiang:'封乡', + jsrgfengxiang_info:'锁定技。当你受到伤害后,你与一名其他角色交换装备区里的所有牌。若你装备区里的牌因此减少,你摸等同于减少牌数的牌。', + jsrg_weiwenzhugezhi:'合卫温诸葛直', + jsrg_weiwenzhugezhi_prefix:'合', + jsrgfuhai:'浮海', + jsrgfuhai_info:'出牌阶段限一次。你可以令所有有手牌的其他角色同时展示一张手牌,然后你选择一个方向并摸X张牌(X为该方向上的角色展示的点数连续严格递增或严格递减的牌数,至少为1)。', + jsrg_zhangxuan:'合张嫙', + jsrg_zhangxuan_prefix:'合', + jsrgtongli:'同礼', + jsrgtongli_info:'当你于出牌阶段内使用基本牌或普通锦囊牌指定第一个目标后,若你手牌中的花色数和你于本阶段内使用过的牌数相等,则你可以展示所有手牌,令此牌额外结算一次。', + jsrgshezang:'奢葬', + jsrgshezang_info:'每轮限一次。当你或你回合内的其他角色进入濒死状态时,你可以亮出牌堆顶的四张牌,获得其中任意张花色各不相同的牌。', + jsrg_gaoxiang:'合高翔', + jsrg_gaoxiang_prefix:'合', + jsrgchiying:'驰应', + jsrgchiying_info:'出牌阶段限一次。你可以选择一名角色,令其攻击范围内的其他角色依次弃置一张牌。若以此法弃置的基本牌数不大于其体力值,其获得这些基本牌。', + jsrg_guozhao:'合郭照', + jsrg_guozhao_prefix:'合', + jsrgpianchong:'偏宠', + jsrgpianchong_info:'一名角色的结束阶段,若你于此回合内失去过牌,你可以判定。若结果为红色/黑色,你摸此回合进入弃牌堆的红色/黑色牌数量的牌。', + jsrgzunwei:'尊位', + jsrgzunwei_info:'出牌阶段限一次。你可以选择一名其他角色并选择执行一项,然后移除该选项:1.将手牌数摸至与该角色相同(最多摸五张);2.将其装备牌移至你的装备区,直到你装备区的牌数不少于其;3.将体力值回复至与该角色相同。', xumou_jsrg:'蓄谋', xumou_jsrg_info:'“蓄谋”牌可在判定区内重复存在。判定阶段开始时,你选择一项:⒈使用此牌对应的实体牌,然后本阶段不能再使用此牌名的牌;⒉将所有的“蓄谋”牌置入弃牌堆。', @@ -6336,6 +8302,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ jiangshanrugu_qi:'江山如故·起', jiangshanrugu_cheng:'江山如故·承', jiangshanrugu_zhuan:'江山如故·转', + jiangshanrugu_he:'江山如故·合', }, }; }); diff --git a/character/mobile.js b/character/mobile.js index 07b1b1fe0..37218e870 100644 --- a/character/mobile.js +++ b/character/mobile.js @@ -15391,7 +15391,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ zhanggong:['zhanggong','re_zhanggong'], baosanniang:['xin_baosanniang','re_baosanniang','baosanniang'], heqi:['re_heqi','heqi'], - weiwenzhugezhi:['weiwenzhugezhi','re_weiwenzhugezhi'], + weiwenzhugezhi:['weiwenzhugezhi','re_weiwenzhugezhi','jsrg_weiwenzhugezhi'], xugong:['xugong','re_xugong','jsrg_xugong'], liuzan:['re_liuzan','liuzan'], sufei:['yj_sufei','sp_sufei','xf_sufei'], diff --git a/character/offline.js b/character/offline.js index 97b416cd8..088f1832a 100644 --- a/character/offline.js +++ b/character/offline.js @@ -886,25 +886,39 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, pshengwu:{ audio:'hengwu', + mod:{ + aiOrder:(player,card,num)=>{ + if(num>0&&get.tag(card,'draw')&&ui.cardPile.childNodes.length+ui.discardPile.childNodes.length<20) return 0; + }, + aiValue:(player,card,num)=>{ + if(num>0&&card.name==='zhuge') return 20; + }, + aiUseful:(player,card,num)=>{ + if(num>0&&card.name==='zhuge') return 10; + } + }, trigger:{player:['useCard','respond']}, direct:true, + locked:false, filter:function(event,player){ return game.hasPlayer(i=>i.countCards('ej',cardx=>get.type(cardx)=='equip'&&get.suit(event.card)==get.suit(cardx))); }, content:function(){ 'step 0' - var suit=get.suit(trigger.card); - var prompt2='弃置任意张'+get.translation(suit)+'手牌,然后摸X张牌(X为你弃置的牌数+'+game.filterPlayer().map(i=>i.countCards('ej',cardx=>get.type(cardx)=='equip'&&get.suit(trigger.card)==get.suit(cardx))).reduce((p,c)=>p+c)+')'; + var suit=get.suit(trigger.card),extra=game.filterPlayer().map(i=>i.countCards('ej',cardx=>{ + return get.type(cardx)=='equip'&&get.suit(trigger.card)==get.suit(cardx); + })).reduce((p,c)=>p+c); + var prompt2='弃置任意张'+get.translation(suit)+'手牌,然后摸X张牌(X为你弃置的牌数+'+extra+')'; player.chooseToDiscard('h',[1,player.countCards('h',{suit:suit})],{suit:suit}).set('prompt',get.prompt('pshengwu')).set('prompt2',prompt2).set('ai',card=>{ - var player=_status.event.player; + if(_status.event.tie) return 0; + let player=_status.event.player; if(_status.event.goon) return 12-get.value(card); - if(player.countCards('h')>50) return 0; if(player==_status.currentPhase){ if(['shan','caochuan','tao','wuxie'].includes(card.name)) return 8-get.value(card); return 6-get.value(card); } return 5.5-get.value(card); - }).set('goon',player.countCards('h',{suit:suit})==1).set('logSkill','pshengwu'); + }).set('goon',player.countCards('h',{suit:suit})==1).set('tie',extra>ui.cardPile.childNodes.length+ui.discardPile.childNodes.length).set('logSkill','pshengwu'); 'step 1' if(result.bool){ var num=result.cards.length; @@ -2649,7 +2663,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, ai:{ order:function(item,player){ - var num=player.getStorage('zyquanji').length; + var num=player.getExpansions('zyquanji').length; if(num==1) return 8; return 1; }, diff --git a/character/rank.js b/character/rank.js index 15033c82b..6a0e44615 100644 --- a/character/rank.js +++ b/character/rank.js @@ -987,6 +987,7 @@ window.noname_character_rank={ 'libai', 'tw_gongsunfan', 'yue_caiwenji', + 'yue_xiaoqiao', 'vtb_xiaole', 'vtb_xiaojiu', 'ol_zhangzhang', @@ -1817,6 +1818,7 @@ window.noname_character_rank={ 'caoxian', ], epic:[ + 'yue_xiaoqiao', 'mb_chengui', 'ol_pengyang', 'ol_luyusheng', diff --git a/character/refresh.js b/character/refresh.js index 4e75e2c6a..71930bb29 100755 --- a/character/refresh.js +++ b/character/refresh.js @@ -6656,7 +6656,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, ai:{ order:function(item,player){ - var num=player.getStorage('gzquanji').length; + var num=player.getExpansions('gzquanji').length; if(num==1) return 8; return 1; }, diff --git a/character/sb.js b/character/sb.js index 8950fa6d1..be73a07b3 100644 --- a/character/sb.js +++ b/character/sb.js @@ -709,7 +709,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ audio:'sbkanpo', trigger:{global:'useCard'}, filter:function(event,player){ - return event.player!=player&&player.getStorage('sbkanpo').includes(event.card.name); + return event.player!=player&&player.storage.sbkanpo[1].includes(event.card.name); }, prompt2:function(event,player){ return '移除'+get.translation(event.card.name)+'的记录,令'+get.translation(event.card)+'无效'; diff --git a/character/shenhua.js b/character/shenhua.js index 34750ef38..222262139 100755 --- a/character/shenhua.js +++ b/character/shenhua.js @@ -3667,7 +3667,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ target:function(card,player,target,current){ if(typeof card==='object'&&get.name(card)==='sha'&&target.mayHaveShan(player,'use')) return [0.6,0.75]; if(!target.hasFriend()&&!player.hasUnknown()) return; - if(_status.currentPhase==target) return; + if(_status.currentPhase==target||get.type(card)==='delay') return; if(card.name!='shuiyanqijunx'&&get.tag(card,'loseCard')&&target.countCards('he')){ if(target.hasSkill('ziliang')) return 0.7; return [0.5,Math.max(2,target.countCards('h'))]; @@ -7714,7 +7714,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ dongzhuo:['dongzhuo','ol_dongzhuo','re_dongzhuo','sp_dongzhuo','yj_dongzhuo'], dengai:['dengai','ol_dengai','re_dengai'], sp_ol_zhanghe:['sp_ol_zhanghe','yj_zhanghe','sp_zhanghe','jsrg_zhanghe'], - jiangwei:['jiangwei','ol_jiangwei','re_jiangwei','sb_jiangwei'], + jiangwei:['jiangwei','ol_jiangwei','re_jiangwei','sb_jiangwei','jsrg_jiangwei'], liushan:['liushan','ol_liushan','re_liushan'], sunce:['sunce','re_sunce','re_sunben','sb_sunce'], zhangzhang:['zhangzhang','ol_zhangzhang','re_zhangzhang'], diff --git a/character/sp.js b/character/sp.js index 69ad799e9..5627da30a 100755 --- a/character/sp.js +++ b/character/sp.js @@ -727,7 +727,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ var {result:{bool,targets}}=await player.chooseTarget(get.prompt2('olgongjie'),[1,num],lib.filter.notMe).set('ai',target=>get.attitude(_status.event.player,target)); if(!bool) return; targets=targets.sortBySeat(); - player.logSkill('gongjie',targets); + player.logSkill('olgongjie',targets); for(var target of targets){ var {result:{bool,cards}}=await target.gainPlayerCard(player,true,'he'); if(bool) draws.add(get.suit(cards[0],player)); @@ -788,6 +788,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){ return player.countCards('he'); }, direct:true, + limited:true, + skillAnimation:true, + animationColor:'water', async content(event,trigger,player){ var target=_status.currentPhase,num=player.countCards('he'); var {result:{bool,cards}}=await player.chooseToGive(get.prompt2('olxiangzuo',target),[1,num],'he').set('ai',card=>{ @@ -951,7 +954,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ forced:true, content:function(){ 'step 0' - player.addTempSkill('olsilv'+(trigger.getg?'gain':'lose')); + player.addTempSkill('olsilv_'+(trigger.getg?'gain':'lose')); if(!trigger.visible){ var cards,name=player.storage.ollianju; if(trigger.getg) cards=trigger.getg(player).filter(card=>card.name==name); @@ -13357,7 +13360,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ audio:2, direct:true, filter:function(event,player){ - return player!=event.player&&!event.player.isDisabledJudge()&&event.player.countCards('he')&&!event.player.countCards('j'); + return player!=event.player&&!event.player.isDisabledJudge()&&event.player.countCards('he')&&!event.player.countCards('j',{type:'delay'}); }, content:function(){ 'step 0' @@ -26329,7 +26332,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ retuogu:'托孤', retuogu_info:'一名角色死亡时,你可以令其选择其武将牌上的一个技能(主公技,限定技,觉醒技,隐匿技、使命技等特殊技能除外),然后你获得其选择的技能并失去上次因〖托孤〗获得的技能。', shanzhuan:'擅专', - shanzhuan_info:'当你对其他角色造成伤害后,若其判定区没有牌,则你可以将其的一张牌置于其的判定区。若此牌不为延时锦囊牌且此牌为:红色,此牌视为【乐不思蜀】;黑色,此牌视为【兵粮寸断】。回合结束时,若你本回合内未造成伤害,你可摸一张牌。', + shanzhuan_info:'①当你对其他角色造成伤害后,若其判定区没有延时类锦囊牌,则你可以将其的一张牌置于其的判定区。若此牌不为延时锦囊牌且此牌为:红色,此牌视为【乐不思蜀】;黑色,此牌视为【兵粮寸断】。②回合结束时,若你本回合内未造成伤害,你可摸一张牌。', spniluan:'逆乱', spniluan_info:'出牌阶段,你可以将一张黑色牌当做【杀】使用。此【杀】使用结算完成后,若你未因此【杀】造成过伤害,则你令此【杀】不计入使用次数。', spweiwu:'违忤', diff --git a/character/sp2.js b/character/sp2.js index a43f80794..0acd2355c 100644 --- a/character/sp2.js +++ b/character/sp2.js @@ -451,6 +451,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ trigger:{player:'phaseEnd',global:'die'}, filter:function(event,player){ if(event.name=='phase') return player.hasMark('starpizhi'); + if(!player.getStorage('starcanxi_wangsheng').includes(event.player.group)&&!player.getStorage('starcanxi_xiangsi').includes(event.player.group)) return false; var groups=player.getSkills().filter(skill=>skill.indexOf('starcanxi_')==0); groups=groups.map(group=>group.slice(10)); return groups.includes(event.player.group); @@ -11181,7 +11182,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ starcanxi_cancel:'向死', starcanxi_info:'锁定技。游戏开始时,你获得场上所有角色的势力对应的“玺角”标记,然后选择一个“玺角”对应势力并选择以下一项;一轮开始时,你选择一个“玺角”对应势力并选择以下一项:①妄生:本轮被选择势力角色每回合首次造成的伤害+1且计算与其他角色间的距离-1;②向死:本轮其他被选择势力角色每回合首次回复体力后失去1点体力且每回合对你使用的第一张牌无效。', starpizhi:'圮秩', - starpizhi_info:'锁定技。①一名角色死亡后,若你拥有该角色对应的“玺角”标记,你失去之并摸X张牌。②结束阶段,你摸X张牌。(X为你本局游戏失去的“玺角”标记数)', + starpizhi_info:'锁定技。①一名角色死亡后,若你拥有该角色对应的“玺角”标记且你本轮发动〖向死〗的势力与其相同,你失去之并摸X张牌。②结束阶段,你摸X张牌。(X为你本局游戏失去的“玺角”标记数)', starzhonggu:'冢骨', starzhonggu_info:'主公技,锁定技。摸牌阶段,若游戏轮数大于等于场上的群势力角色数,则你额外摸两张牌,否则你少摸一张牌。', star_dongzhuo:'星董卓', diff --git a/character/standard.js b/character/standard.js index a026971f6..913afa23f 100755 --- a/character/standard.js +++ b/character/standard.js @@ -1,4 +1,4 @@ -'use strict'; +import { game } from '../noname.js'; game.import('character',function(lib,game,ui,get,ai,_status){ return { name:'standard', @@ -93,6 +93,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){ ganning:['lingtong','xf_sufei'], guanyu:['zhangfei','liaohua'], }, + /** + * @type { { [key: string]: Skill } } + */ skill:{ //标准版甘夫人 stdshushen:{ @@ -304,7 +307,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ logTarget:'source', preHidden:true, filter(event,player){ - return (event.source&&event.source.countGainableCards(player,event.source!=player?'he':'e')&&event.num>0); + return event.source&&event.source.countGainableCards(player,event.source!=player?'he':'e')>0&&event.num>0; }, async content(event,trigger,player){ player.gainPlayerCard(true,trigger.source,trigger.source!=player?'he':'e'); @@ -1761,9 +1764,9 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, async content(event,trigger,player){ event.count=trigger.getl(player).es.length; - do { + while(event.count-->0){ player.draw(2); - if(!player.hasSkill(event.name)) break; + if(!event.count||!player.hasSkill(event.name)) break; if(!get.is.blocked(event.name,player)){ const chooseBoolEvent=player.chooseBool(get.prompt2('xiaoji')).set('frequentSkill','xiaoji'); chooseBoolEvent.ai=lib.filter.all; @@ -1771,7 +1774,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ if(bool) player.logSkill('xiaoji'); else break; } - }while(event.count-->0); + } }, ai:{ noe:true, @@ -2325,7 +2328,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ characterReplace:{ caocao:['caocao','re_caocao','sb_caocao','dc_caocao'], guojia:['guojia','re_guojia','ps1059_guojia','ps2070_guojia'], - simayi:['simayi','re_simayi','ps_simayi','ps2068_simayi'], + simayi:['simayi','re_simayi','jsrg_simayi','ps_simayi','ps2068_simayi'], jin_simayi:['jin_simayi','junk_simayi','ps_jin_simayi'], zhenji:['zhenji','re_zhenji','sb_zhenji','yj_zhenji'], xuzhu:['xuzhu','re_xuzhu'], @@ -2335,15 +2338,15 @@ game.import('character',function(lib,game,ui,get,ai,_status){ liubei:['liubei','re_liubei','sb_liubei','dc_liubei','junk_liubei'], guanyu:['guanyu','re_guanyu','ps_guanyu','old_guanyu'], zhangfei:['zhangfei','re_zhangfei','old_zhangfei','xin_zhangfei','sb_zhangfei','tw_zhangfei','jsrg_zhangfei','yj_zhangfei'], - zhaoyun:['zhaoyun','re_zhaoyun','old_zhaoyun','sb_zhaoyun','ps2063_zhaoyun','ps2067_zhaoyun'], + zhaoyun:['zhaoyun','re_zhaoyun','old_zhaoyun','sb_zhaoyun','jsrg_zhaoyun','ps2063_zhaoyun','ps2067_zhaoyun'], sp_zhaoyun:['sp_zhaoyun','jsp_zhaoyun'], machao:['machao','re_machao','sb_machao','ps_machao'], sp_machao:['sp_machao','dc_sp_machao','jsrg_machao','old_machao'], - zhugeliang:['zhugeliang','re_zhugeliang','ps2066_zhugeliang','ps_zhugeliang','sb_zhugeliang'], + zhugeliang:['zhugeliang','re_zhugeliang','sb_zhugeliang','jsrg_zhugeliang','ps2066_zhugeliang','ps_zhugeliang'], huangyueying:['huangyueying','re_huangyueying','junk_huangyueying','sb_huangyueying'], sunquan:['sunquan','re_sunquan','sb_sunquan','dc_sunquan'], zhouyu:['zhouyu','re_zhouyu','sb_zhouyu','ps1062_zhouyu','ps2080_zhouyu'], - luxun:['luxun','re_luxun'], + luxun:['luxun','re_luxun','jsrg_luxun'], lvmeng:['lvmeng','re_lvmeng','sb_lvmeng'], huanggai:['huanggai','re_huanggai','sb_huanggai'], daqiao:['daqiao','re_daqiao','sb_daqiao'], diff --git a/character/tw.js b/character/tw.js index dc2404dcd..bd06292b8 100644 --- a/character/tw.js +++ b/character/tw.js @@ -77,7 +77,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ tw_madai:['male','shu',4,['mashu','twqianxi']], tw_niujin:['male','wei',4,['twcuorui','twliewei']], tw_guanqiujian:['male','wei',3,['twzhengrong','twhongju']], - tw_daxiaoqiao:['female','wu',3,['twxingwu','twpingting']], + tw_daxiaoqiao:['female','wu',3,['twxingwu','twpingting'],['tempname:daxiaoqiao']], tw_furong:['male','shu',4,['twxuewei','twliechi']], tw_yl_luzhi:['male','qun',3,['twmingren','twzhenliang']], tw_liuzhang:['male','qun',3,['jutu','twyaohu','rehuaibi']], @@ -364,12 +364,12 @@ game.import('character',function(lib,game,ui,get,ai,_status){ event.target=target; var list=['cancel2']; var choiceList=[ - '弃置一张手牌,令此【杀】可以额外指定一个目标', + '令此【杀】可以额外指定一个目标', '弃置其一张手牌,若此【杀】造成伤害,则你摸一张牌且本阶段可以额外使用一张【杀】', ]; if(target.countCards('h')) list.unshift('其弃置'); else choiceList[1]=''+choiceList[1]+''; - if(game.hasPlayer(targetx=>!trigger.targets.includes(targetx)&&player.canUse(trigger.card,targetx))) list.unshift('你弃置'); + if(game.hasPlayer(targetx=>!trigger.targets.includes(targetx)&&player.canUse(trigger.card,targetx))) list.unshift('多指'); else choiceList[0]=''+choiceList[0]+''; player.chooseControl(list).set('choiceList',choiceList).set('ai',()=>{ var controls=_status.event.controls; @@ -377,7 +377,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ var player=trigger.player; var target=trigger.target; if(controls.includes('其弃置')&&_status.event.goon) return '其弃置'; - if(controls.includes('你弃置')){ + if(controls.includes('多指')){ if(game.hasPlayer(targetx=>!trigger.targets.includes(targetx)&&player.canUse(trigger.card,targetx)&&get.effect(targetx,trigger.card,player,player)>0)) return '你弃置'; } return 'cancel2'; @@ -6240,7 +6240,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ audio:2, trigger:{global:['roundStart','dying']}, init:function(player,skill){ - if(player.getExpansions('twxingwu').length) player.addAdditionalSkill(skill,['tianxiang_daxiaoqiao','liuli_daxiaoqiao']); + if(player.getExpansions('twxingwu').length) player.addAdditionalSkill(skill,['tianxiang','liuli']); else player.removeAdditionalSkill(skill); }, filter:function(event,player){ @@ -6269,18 +6269,13 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, subSkill:{ update:{ - trigger:{ - player:['loseAfter','loseAsyncAfter','addToExpansionAfter'], + trigger:{player:['loseAfter','loseAsyncAfter','addToExpansionAfter']}, + filter:function(event,player){ + var cards=player.getExpansions('twxingwu'),skills=player.additionalSkills.twpingting; + return !((cards.length&&skills&&skills.length)||(!cards.length&&(!skills||!skills.length))); }, forced:true, silent:true, - filter:function(event,player){ - var cards=player.getExpansions('twxingwu'),skills=player.additionalSkills.twpingting; - if((cards.length&&skills&&skills.length)||(!cards.length&&(!skills||!skills.length))){ - return false; - } - return true; - }, content:function(){ lib.skill.twpingting.init(player,'twpingting'); } diff --git a/character/xianding.js b/character/xianding.js index 41b0b18e6..a958de99c 100644 --- a/character/xianding.js +++ b/character/xianding.js @@ -20,7 +20,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ dc_sp_machao:['male','qun',4,['zhuiji','dc_olshichou']], old_huangfusong:['male','qun',4,['xinfenyue']], dc_xiahouba:['male','shu',4,['rebaobian']], - dc_daxiaoqiao:['female','wu',3,['dcxingwu','dcluoyan']], + dc_daxiaoqiao:['female','wu',3,['dcxingwu','dcluoyan'],['tempname:daxiaoqiao']], tianshangyi:['female','wei',3,['dcposuo','dcxiaoren']], sunlingluan:['female','wu',3,['dclingyue','dcpandi']], dc_wangjun:['male','qun',4,['dctongye','dcchangqu']], @@ -145,10 +145,6 @@ game.import('character',function(lib,game,ui,get,ai,_status){ return (dis?6:1)-get.useful(card); } if(_status.event.hvt.includes(card)){ - if(_status.event.suits.length>=4){ - if(cards.length>8) return 0; - return 4.5-get.value(card); - } if(!_status.event.suits.includes(suit)) return 6-get.value(card); if(card.name==='sha') return 3-get.value(card); return 1-get.value(card); @@ -1306,6 +1302,17 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, dczhangcai:{ audio:2, + mod:{ + aiOrder:(player,card,num)=>{ + if(num>0&&get.tag(card,'draw')&&ui.cardPile.childNodes.length+ui.discardPile.childNodes.length<20) return 0; + }, + aiValue:(player,card,num)=>{ + if(num>0&&card.name==='zhuge') return 20; + }, + aiUseful:(player,card,num)=>{ + if(num>0&&card.name==='zhuge') return 10; + } + }, trigger:{ player:['useCard','respond'], }, @@ -1319,7 +1326,14 @@ game.import('character',function(lib,game,ui,get,ai,_status){ if(typeof num=='number') count=Math.max(1,player.countCards('h',card=>get.number(card)==num)) return '你可以摸'+get.cnNumber(count)+'张牌。'; }, + check:(event,player)=>{ + const num=player.hasSkill('dczhangcai_all')?get.number(event.card):8; + let count=1; + if(typeof num=='number') count=Math.max(1,player.countCards('h',card=>get.number(card)==num)); + return ui.cardPile.childNodes.length+ui.discardPile.childNodes.length>=count; + }, frequent:true, + locked:false, content:function(){ var num=player.hasSkill('dczhangcai_all')?get.number(trigger.card):8; var count=1; @@ -1649,33 +1663,29 @@ game.import('character',function(lib,game,ui,get,ai,_status){ } }, }, - dcluoyan: { - derivation: ['retianxiang', 'liuli'], - init: function (player) { - if (player.getStorage('dcxingwu').length) player.addAdditionalSkill('dcluoyan', ['retianxiang_daxiaoqiao', 'liuli_daxiaoqiao']); + dcluoyan:{ + derivation:['retianxiang','liuli'], + init:function(player){ + if(player.getExpansions('dcxingwu').length) player.addAdditionalSkill('dcluoyan',['retianxiang','liuli']); else player.removeAdditionalSkill('dcluoyan'); }, - onremove: function (player) { + onremove:function(player){ player.removeAdditionalSkill('dcluoyan'); }, - trigger: { - player: ['loseAfter', 'loseAsyncAfter', 'addToExpansionAfter'], + trigger:{player:['loseAfter','loseAsyncAfter','addToExpansionAfter']}, + filter:function(event,player){ + var cards=player.getExpansions('dcxingwu'),skills=player.additionalSkills.dcluoyan; + return !((cards.length&&skills&&skills.length)||(!cards.length&&(!skills||!skills.length))); }, - filter: function (event, player) { - var cards = player.getExpansions('dcxingwu'), skills = player.additionalSkills.dcluoyan; - if ((cards.length && skills && skills.length) || (!cards.length && (!skills || !skills.length))) { - return false; - } - return true; - }, - forced: true, - content: function () { - lib.skill.twpingting.init(player, 'dcluoyan'); + forced:true, + silent:true, + content:function(){ + lib.skill.dcluoyan.init(player,'dcluoyan'); }, }, - retianxiang_daxiaoqiao: { - audio: 'tianxiang_daxiaoqiao', - inherit: 'retianxiang', + retianxiang_daxiaoqiao:{ + audio:'tianxiang_daxiaoqiao', + inherit:'retianxiang', }, //田尚衣 dcposuo:{ @@ -13514,7 +13524,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ fengfangnv:['fengfangnv','re_fengfangnv'], luotong:['dc_luotong','luotong'], dc_wangchang:['dc_wangchang','tw_wangchang'], - guozhao:['guozhao','xin_guozhao'], + guozhao:['guozhao','xin_guozhao','jsrg_guozhao'], dingshangwan:['dingshangwan','ol_dingshangwan'], }, translate:{ diff --git a/game/asset.js b/game/asset.js index f8670e51a..0d0ce7d8a 100644 --- a/game/asset.js +++ b/game/asset.js @@ -1,5 +1,5 @@ window.noname_asset_list=[ - 'v1.10.6', + 'v1.10.6.1', /*audio start*/ 'audio/background/aozhan_chaoming.mp3', 'audio/background/aozhan_online.mp3', @@ -7237,30 +7237,41 @@ window.noname_asset_list=[ 'image/character/jsp_liubei.jpg', 'image/character/jsp_zhaoyun.jpg', 'image/character/jsrg_caocao.jpg', + 'image/character/jsrg_caofang.jpg', 'image/character/jsrg_chendeng.jpg', 'image/character/jsrg_chunyuqiong.jpg', 'image/character/jsrg_dongbai.jpg', 'image/character/jsrg_fanjiangzhangda.jpg', + 'image/character/jsrg_gaoxiang.jpg', 'image/character/jsrg_guanyu.jpg', 'image/character/jsrg_guojia.jpg', + 'image/character/jsrg_guoxun.jpg', + 'image/character/jsrg_guozhao.jpg', 'image/character/jsrg_hansui.jpg', 'image/character/jsrg_hejin.jpg', 'image/character/jsrg_huangfusong.jpg', 'image/character/jsrg_huangzhong.jpg', + 'image/character/jsrg_jiangwei.jpg', 'image/character/jsrg_kongrong.jpg', 'image/character/jsrg_liubei.jpg', 'image/character/jsrg_liuhong.jpg', 'image/character/jsrg_liuyan.jpg', + 'image/character/jsrg_liuyong.jpg', 'image/character/jsrg_lougui.jpg', + 'image/character/jsrg_luxun.jpg', 'image/character/jsrg_lvbu.jpg', 'image/character/jsrg_machao.jpg', 'image/character/jsrg_nanhualaoxian.jpg', 'image/character/jsrg_pangtong.jpg', 'image/character/jsrg_qiaoxuan.jpg', + 'image/character/jsrg_simayi.jpg', 'image/character/jsrg_sunce.jpg', 'image/character/jsrg_sunjian.jpg', + 'image/character/jsrg_sunjun.jpg', + 'image/character/jsrg_sunlubansunluyu.jpg', 'image/character/jsrg_sunshangxiang.jpg', 'image/character/jsrg_wangyun.jpg', + 'image/character/jsrg_weiwenzhugezhi.jpg', 'image/character/jsrg_xiahouen.jpg', 'image/character/jsrg_xiahourong.jpg', 'image/character/jsrg_xugong.jpg', @@ -7272,7 +7283,10 @@ window.noname_asset_list=[ 'image/character/jsrg_zhanghe.jpg', 'image/character/jsrg_zhangliao.jpg', 'image/character/jsrg_zhangren.jpg', + 'image/character/jsrg_zhangxuan.jpg', + 'image/character/jsrg_zhaoyun.jpg', 'image/character/jsrg_zhenji.jpg', + 'image/character/jsrg_zhugeliang.jpg', 'image/character/jsrg_zhujun.jpg', 'image/character/jsrg_zoushi.jpg', 'image/character/jun_caocao.jpg', diff --git a/game/game.js b/game/game.js index 73ccd3c7e..04ba0207d 100644 --- a/game/game.js +++ b/game/game.js @@ -91,7 +91,7 @@ new Promise(resolve => { script.async = true script.onerror = (event) => { console.error(event) - const message = `您使用的浏览器或无名杀客户端加载内容失败!\n若您使用的客户端为自带内核的旧版“兼容版”,请及时更新客户端版本!\n若您使用的客户端为手机端的非兼容版无名杀,请尝试更新手机端WebView内核,或者更换为1.8.2版本以上的兼容版!`; + const message = `您使用的浏览器或《无名杀》客户端加载内容失败!\n若您使用的客户端为自带内核的旧版“兼容版”,请及时更新客户端版本!\n若您使用的客户端为手机端的非兼容版《无名杀》,请尝试更新手机的WebView内核,或者更换为1.8.2版本及以上的兼容版!\n若您是直接使用浏览器加载index.html进行游戏,请改为运行文件夹内的“noname-server.exe”(或使用VSCode等工具启动Live Server),以动态服务器的方式启动《无名杀》!`; console.error(message); alert(message); exit() diff --git a/game/update.js b/game/update.js index 7c18fdd0b..4be954e40 100644 --- a/game/update.js +++ b/game/update.js @@ -1,137 +1,56 @@ window.noname_update={ - version:'1.10.6', - update:'1.10.5', + version:'1.10.6.1', + update:'1.10.6', changeLog:[ - '整合@nonameShijian @mengxinzxz @PZ157 @Ansolve @Rintim @S-N-O-R-L-A-X @universe-st @copcap @kuangshen04 的Pull Request', - '拆分game.js,优化代码逻辑与可读性', - '孙策(十周年斗地主)、乐小乔、手杀陈珪、手杀胡班、OL界凌统、OL界曹彰、OL界简雍、OL谋姜维、谋诸葛亮、谋关羽、曹宇、星董卓、曹宪、新杀谋鲁肃、新杀谋周瑜', + '整合@mengxinzxz @PZ157 @universe-st @Ansolve @Rintim @nonameShijian @copcap @kuangshen04 的Pull Request', + '《江山如故·合》武将包', '其他AI优化与bug修复', ], files:[ - 'card/extra.js', - 'card/gujian.js', - 'card/guozhan.js', - 'card/gwent.js', - 'card/hearth.js', - 'card/huanlekapai.js', - 'card/mtg.js', - 'card/sp.js', 'card/standard.js', - 'card/swd.js', - 'card/yingbian.js', 'card/yongjian.js', - 'card/yunchou.js', - 'card/zhenfa.js', - 'card/zhulu.js', - 'character/clan.js', - 'character/collab.js', - 'character/ddd.js', - 'character/diy.js', 'character/extra.js', - 'character/gujian.js', - 'character/gwent.js', - 'character/hearth.js', 'character/huicui.js', - 'character/jiange.js', 'character/jsrg.js', 'character/mobile.js', - 'character/mtg.js', 'character/offline.js', - 'character/old.js', - 'character/onlyOL.js', - 'character/ow.js', 'character/rank.js', 'character/refresh.js', 'character/sb.js', 'character/shenhua.js', - 'character/shiji.js', 'character/sp.js', 'character/sp2.js', 'character/standard.js', - 'character/swd.js', 'character/tw.js', - 'character/xiake.js', 'character/xianding.js', - 'character/xianjian.js', - 'character/xinghuoliaoyuan.js', - 'character/yijiang.js', - 'character/yingbian.js', - 'character/yxs.js', - - 'extension/boss/extension.js', - 'game/codemirror.js', - 'game/config.js', - 'game/core-js-bundle.js', - 'game/entry.js', 'game/game.js', - 'game/package.js', 'game/source.js', 'mode/boss.js', - 'mode/brawl.js', - 'mode/chess.js', - 'mode/doudizhu.js', - 'mode/guozhan.js', - 'mode/identity.js', - 'mode/realtime.js', - 'mode/single.js', - 'mode/stone.js', - 'mode/tafang.js', - 'mode/versus.js', 'noname.js', - 'noname/ai/basic.js', - 'noname/ai/index.js', 'noname/game/index.js', - 'noname/game/promises.js', - 'noname/game/dynamic-style/index.js', + 'noname/get/index.js', 'noname/get/is.js', - 'noname/gnc/index.js', - 'noname/gnc/is.js', + 'noname/init/cordova.js', 'noname/init/import.js', 'noname/init/index.js', - 'noname/init/node.js', - 'noname/init/onload.js', - 'noname/init/polyfill.js', + 'noname/library/index.js', - 'noname/library/path.js', - 'noname/library/announce/index.d.ts', - 'noname/library/announce/index.js', - 'noname/library/channel/index.js', - 'noname/library/element/button.js', - 'noname/library/element/card.js', - 'noname/library/element/client.js', + 'noname/library/element/content.js', - 'noname/library/element/contents.js', - 'noname/library/element/control.js', - 'noname/library/element/dialog.js', 'noname/library/element/gameEvent.js', 'noname/library/element/gameEventPromise.js', - 'noname/library/element/index.js', - 'noname/library/element/nodeWS.js', - 'noname/library/element/player.js', 'noname/library/element/vcard.js', - 'noname/library/experimental/index.js', - 'noname/library/experimental/symbol.js', - 'noname/library/init/index.js', - 'noname/library/init/promises.js', - 'noname/status/index.js', + 'noname/ui/index.js', - 'noname/util/browser.js', - 'noname/util/config.js', - 'noname/util/index.js', - 'noname/util/mutex.js', - 'noname/util/struct/index.js', - 'noname/util/struct/interface/index.d.ts', - 'noname/util/struct/interface/promise-error-handler.d.ts', + 'noname/util/struct/promise-error-handler/chrome.js', - 'noname/util/struct/promise-error-handler/firefox.js', - 'noname/util/struct/promise-error-handler/index.js', 'noname/util/struct/promise-error-handler/unknown.js', ] }; diff --git a/image/card/xumou_jsrg.jpg b/image/card/xumou_jsrg.jpg index 109581254..2171863ec 100644 Binary files a/image/card/xumou_jsrg.jpg and b/image/card/xumou_jsrg.jpg differ diff --git a/image/character/jsrg_caofang.jpg b/image/character/jsrg_caofang.jpg new file mode 100644 index 000000000..c9260f90b Binary files /dev/null and b/image/character/jsrg_caofang.jpg differ diff --git a/image/character/jsrg_gaoxiang.jpg b/image/character/jsrg_gaoxiang.jpg new file mode 100644 index 000000000..d2abd8ec8 Binary files /dev/null and b/image/character/jsrg_gaoxiang.jpg differ diff --git a/image/character/jsrg_guoxun.jpg b/image/character/jsrg_guoxun.jpg new file mode 100644 index 000000000..41868b5d3 Binary files /dev/null and b/image/character/jsrg_guoxun.jpg differ diff --git a/image/character/jsrg_guozhao.jpg b/image/character/jsrg_guozhao.jpg new file mode 100644 index 000000000..cf5826644 Binary files /dev/null and b/image/character/jsrg_guozhao.jpg differ diff --git a/image/character/jsrg_jiangwei.jpg b/image/character/jsrg_jiangwei.jpg new file mode 100644 index 000000000..29b66240e Binary files /dev/null and b/image/character/jsrg_jiangwei.jpg differ diff --git a/image/character/jsrg_liuyong.jpg b/image/character/jsrg_liuyong.jpg new file mode 100644 index 000000000..57363374f Binary files /dev/null and b/image/character/jsrg_liuyong.jpg differ diff --git a/image/character/jsrg_luxun.jpg b/image/character/jsrg_luxun.jpg new file mode 100644 index 000000000..0e74a3d3c Binary files /dev/null and b/image/character/jsrg_luxun.jpg differ diff --git a/image/character/jsrg_simayi.jpg b/image/character/jsrg_simayi.jpg new file mode 100644 index 000000000..219bc25a1 Binary files /dev/null and b/image/character/jsrg_simayi.jpg differ diff --git a/image/character/jsrg_sunjun.jpg b/image/character/jsrg_sunjun.jpg new file mode 100644 index 000000000..659080375 Binary files /dev/null and b/image/character/jsrg_sunjun.jpg differ diff --git a/image/character/jsrg_sunlubansunluyu.jpg b/image/character/jsrg_sunlubansunluyu.jpg new file mode 100644 index 000000000..86656bc1a Binary files /dev/null and b/image/character/jsrg_sunlubansunluyu.jpg differ diff --git a/image/character/jsrg_weiwenzhugezhi.jpg b/image/character/jsrg_weiwenzhugezhi.jpg new file mode 100644 index 000000000..6d591a206 Binary files /dev/null and b/image/character/jsrg_weiwenzhugezhi.jpg differ diff --git a/image/character/jsrg_zhangxuan.jpg b/image/character/jsrg_zhangxuan.jpg new file mode 100644 index 000000000..6e877f117 Binary files /dev/null and b/image/character/jsrg_zhangxuan.jpg differ diff --git a/image/character/jsrg_zhaoyun.jpg b/image/character/jsrg_zhaoyun.jpg new file mode 100644 index 000000000..1b7d747a2 Binary files /dev/null and b/image/character/jsrg_zhaoyun.jpg differ diff --git a/image/character/jsrg_zhugeliang.jpg b/image/character/jsrg_zhugeliang.jpg new file mode 100644 index 000000000..4b16a866b Binary files /dev/null and b/image/character/jsrg_zhugeliang.jpg differ diff --git a/index.html b/index.html index ffa1fcf2b..abe49f125 100755 --- a/index.html +++ b/index.html @@ -7,7 +7,7 @@ 无名杀 + diff --git a/mode/boss.js b/mode/boss.js index 9b01e7c20..36dabf984 100644 --- a/mode/boss.js +++ b/mode/boss.js @@ -8818,7 +8818,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } function isDefined(opd) { if(opd!=undefined){ - if (opd.get||opd.set||opd.writable!=true||opd.configurable!=true||opd.enumerable!=true){ + if (opd.get||opd.set||opd.writable!=true||opd.configurable!=true){ return true; } } diff --git a/node_modules/noname-typings/Card.d.ts b/node_modules/noname-typings/Card.d.ts new file mode 100644 index 000000000..07d0ce051 --- /dev/null +++ b/node_modules/noname-typings/Card.d.ts @@ -0,0 +1,23 @@ +declare type CardBaseUIData = { + name?: string; + suit?: string; + number?: number; + nature?: string; + + //用于某些方法,用于过滤卡牌的额外结构 + type?: string; + subtype?: string; + color?: string; + + /** + * 是否时视为牌 + * + * 是本来的卡牌,则为true,作为视为牌则为false/undefined + * 在useCard使用时,作为视为牌,会把next.cards,设置为card.cards; + * + */ + isCard?: boolean; + + /** 真实使用的卡牌 */ + cards?: Card[]; +} \ No newline at end of file diff --git a/node_modules/noname-typings/Result.d.ts b/node_modules/noname-typings/Result.d.ts new file mode 100644 index 000000000..24bfb85aa --- /dev/null +++ b/node_modules/noname-typings/Result.d.ts @@ -0,0 +1,43 @@ +declare interface Result { + /** + * 最终结果 + * + * 大多代表该事件到达这一步骤过程中的结果; + * 一般用来标记当前事件是否按预定执行的,即执行成功 + * + * 大部分事件间接接触game.check,一般最终结果不变,大多数是这种 + * + * 其实主要是ok方法会有直接的bool,主要涉及game.check; + */ + bool?: boolean; + + //choose系 + /** 记录返回当前事件操作过程中的卡牌 */ + cards: Card[]; + /** 记录返回当前事件操作过程中的目标 */ + targets: Player[]; + /** 记录返回当前事件操作过程中的按钮 */ + buttons: Button[]; + /** 记录buttons内所有button.link(即该按钮的类型,link的类型很多,参考按钮的item) */ + links: any[]; + + //control系(直接control系列没有result.bool) + /** control操作面板的选中结果,即该按钮的link,即名字 */ + control: string; + /** 既control的下标 */ + index: number; + + //ok系 + /** 记录返回当前事件操作过程中,面板按钮的确定ok取消cancel */ + confirm: string; + /** 一般为触发的“视为”技能 */ + skill: string; + /** + * 当前事件操作的“视为”牌, + * 当前有“视为”操作,该card参数特供给视为牌,不需要cards[0]获取视为牌 ; + * 判断是否为视为牌:card.isCard,false为视为牌 + */ + card: Card; + + [key: string]: any; +} \ No newline at end of file diff --git a/node_modules/noname-typings/Skill.d.ts b/node_modules/noname-typings/Skill.d.ts new file mode 100644 index 000000000..9c1b70514 --- /dev/null +++ b/node_modules/noname-typings/Skill.d.ts @@ -0,0 +1,1820 @@ +/** 时机 */ +declare interface SkillTrigger { + /** + * 全场任意一名角色 + * + * 代表所有人 + */ + global?: string | string[]; + /** + * 玩家自己 + * + * 触发时件中,技能拥有者为事件的发起者; + * + * 注:需要是自己引发的事件; + */ + player?: string | string[]; + /** + * 你自己成为目标时 + */ + target?: string | string[]; + /** + * 来源是你自己时 + */ + source?: string | string[]; +} + +/** + * hookTrigger在不同方法中触发的方法接口 + * + * 注:似乎时用于模式,作为,游戏全局的一些每次都需要触发的方法(算是不实用的一个接口) + */ +declare interface SkillHookTrigger { + /** + * 【hookTrigger相关】 + * + * 之后处理方法 + * + * 在createTrigger中最终步骤中,需要当前没有hookTrigger配置才调用到 + * + * 若返回true时,会触发“triggerAfter” + * + * @param event + * @param player + * @param triggername + */ + after?(event: GameEventPromise, player: Player, triggername: string): boolean; + /** + * 【hookTrigger相关】 + * + * 在filterTrigger中执行,过滤发动条件,和filter有些类似,具体功能稍后分析 + */ + block?(event: GameEventPromise, player: Player, name: string, skill: string): boolean; + /** + * 【hookTrigger相关】 + * + * 在logSkill中执行,每次触发logSkill都会触发 + */ + log?: ThreeParmFun; +} + +/** mod的配置 */ +declare interface Mod { + /** + * 卡牌是否可弃置 + * @param card:Card 牌 + * @param player:Player 玩家 + */ + cardDiscardable?(card: Card, player: Player): boolean | void; + /** + * 卡牌是否可用(卡牌能否被选择) + * cardEnabled一起使用 + * + * 适用范围:player.canUse,lib.filter.cardEnabled,默认lib.filter.filterCard + * + * @param card:Card 牌 + * @param player:Player 玩家 + */ + cardEnabled?(card: Card, player: Player): boolean | void; + /** + * 卡牌是否可用(适用范围基本可以视为所有情况下) + * + * 适用范围:event.backup中技能信息触发(viewAS),cardEnabled(优先于该mod的触发),cardRespondable(优先于该mod的触发),_save(优先于cardSavable的mod触发)中均触发 + */ + cardEnabled2?(card: Card, player: Player): boolean | void; + /** + * 卡牌是否可用(改变卡牌的使用次数) + * + * 要与cardEnabled一起使用(目前看来两个效果一致) + * + * @param card Card 牌 + * @param player Player 玩家 + * @param num 使用次数 + */ + cardUsable?(card: Card, player: Player, num: number): boolean | number | void; + /** + * 卡牌是否可以响应 + * + * 要与cardEnabled一起使用(目前看来两个效果一致) + * + * @param card:Card 牌 + * @param player:Player 玩家 + */ + cardRespondable?(card: Card, player: Player): boolean | void; + /** + * 卡牌是否可以救人 + * + * 要与cardEnabled一起使用(目前看来两个效果一致) + * + * 注:还是和cardEnabled不同,设置了该mod检测,只要是在_save,濒死求救阶段,都可以触发; + * + * 不过前提,可能还是要通过该阶段的cardEnabled的检测,目前还没确定,日后再做分析 + * + * 适用范围:濒死阶段的filterCard + * + * @param card:Card 牌 + * @param player:Player 玩家 + * @param taregt:Target 当前处于濒死求救得玩家 + */ + cardSavable?(card: Card, player: Player, taregt: Player): boolean | void; + /** + * 在全局的防御范围 + * + * 注:防御距离就是要和别人的距离越远,所以,拉开距离需要增加; + */ + globalTo?(from: Player, to: Player, current): number | void; + /** + * 在全局的进攻距离 + * + * 注:进攻距离就是要和别人的距离越近,所以,增加距离需要减掉; + */ + globalFrom?(from: Player, to: Player, distance: number): number | void; + /** + * 角色的攻击范围 + * @param from + * @param to + * @param range + * + * 注:和globalFrom同理,拉近距离,减去; + */ + attackFrom?(from: Player, to: Player, range: number): number | void; + /** + * 攻击到角色的范围 + * @param from + * @param to + * @param range + * + * 注:和globalTo同理,拉开距离,增加; + */ + attackTo?(from: Player, to: Player, range: number): number | void; + /** 手牌上限 */ + maxHandcard?(player: Player, num: number): number | void; + /** + * 选择的目标 + * + * card:牌; + * + * player:玩家; + * + * range: + * range[1]:目标个数; + */ + selectTarget?(card: Card, player: Player, range: Select): void; + + /** + * 该卡牌的发动源玩家是否能使用该卡牌(该角色是否能使用该牌) + * + * @param card:Card + * + * @param player:Player 源玩家(使用牌的角色) + * + * @param target:Target 目标玩家 + */ + playerEnabled?(card: Card, player: Player, target: Player): boolean | void; + /** + * 是否能成为目标 + * + * card:牌; + * + * player:使用牌的角色; + * + * target:玩家 + */ + targetEnabled?(card: Card, player: Player, target: Player): boolean | void; + + /** + * 可以指定任意(范围内)目标 + * + * @param card:Card 牌 + * + * @param player:Player 玩家(使用牌的角色) + * + * @param target:Target 目标 + * + * @return 返回bool值可以不接受,范围检测,使用返回的结果;返回number,即计算距离是增加该距离;不返回,默认正常的范围检测 + */ + targetInRange?(card: Card, player: Player, target: Player): boolean | number | void; + /** + * 弃牌阶段时,忽略的手牌 + * + * @param card:Card + * + * @param player:Player + */ + ignoredHandcard?(card: Card, player: Player): boolean | void; + + /** 过滤可以被丢弃的牌 */ + canBeDiscarded?(card: Card, player: Player, target: Player, eventName: string): boolean | void; + /** 过滤可以获得的牌 */ + canBeGained?(card: Card, player: Player, target: Player, eventName: string): boolean | void; + + /** + * 改变花色 + */ + suit?(card: Card, suit: string): string | void; + /** + * 改变判断结果 + * + * 注:目前似乎没有用到该mod.改变结果不影响判定的牌结果,影响判定的最终结果,即之后判定牌的effect会受该结果影响 + * @param player + * @param result + */ + judge?(player: Player, result: JudgeResultData); + + //2020-2-23版本: + /** + * 为技能配置一个自定义在事件中处理的回调事件,该事件的使用需要自己使用,实际是一个自定义事件,没什么实际意义; + * + * 其设置的位置在技能content期间设置,设置在期间引发的事件中; + * + * 用于以下场合:judge,chooseToCompareMultiple,chooseToCompare + * + * 新版本的judge事件中 可以通过设置callback事件 在judgeEnd和judgeAfter时机之前对判定牌进行操作 + * + * 在判断结果出来后,若事件event.callback存在,则发送“judgeCallback”事件 + * + * 同理拼点,在拼点结果出来后,发送“compareMultiple”事件(“compare”暂时没有) + * + * callback就是作为以上事件的content使用 + */ + callback?: ContentFuncByAll; + + //无懈相关:主要在_wuxie中,(此时应时无懈询问阶段),检测触发卡牌以下对应mod + /* + 主要参数解析: + card:trigger.card 触发该无懈阶段的卡牌; + + player:当前事件的玩家(应该也是触发该阶段的玩家) + + target:trigger.target 触发该无懈阶段的卡牌的玩家; + + current:当前game.filterPlayer,遍历过滤检测可以发动无懈的每一个玩家(即当前过滤检测中的玩家) + */ + //触发阶段为:phaseJudge(判定阶段) + /** 是否能在判定阶段使用无懈 */ + wuxieJudgeEnabled?(card: Card, player: Player, current: Player): boolean | void; + /** 是否能在判定阶段响应无懈 */ + wuxieJudgeRespondable?(card: Card, player: Player, current: Player): boolean | void; + //非判定阶段触发 + /** 是否能使用无懈 */ + wuxieEnabled?(card: Card, player: Player, target: Player, current: Player): boolean | void; + /** 是否能响应无懈 */ + wuxieRespondable?(card: Card, player: Player, target: Player, current: Player): boolean | void; + + //94版本 + /** 改变卡牌名字 用于get.name*/ + cardname?(card: Card, player: Player): string | void; + /** 改变卡牌伤害属性 用于get.nature*/ + cardnature?(card: Card, player: Player): string | void; + + /** 对特定角色使用牌的次数限制(用于优化【对特定角色使用牌无次数限制】的机制)【v1.9.105】 */ + cardUsableTarget?(card: Card, player: Player, target: Player): boolean | void; + + /** 用于get.value,对最后得返回value结果做处理 */ + aiValue?(player: Player, card: Card, num: number): number | void; + /** 用于get.order,对最后得返回order结果做处理 */ + aiOrder?(player: Player, card: Card, num: number): number | void; + + //player.inRange新增: + /** 在玩家范围内,即target是否在player的攻击范围内 */ + inRange?(from: Player, to: Player): boolean | void; + /** 在目标范围内,即player是否在source的攻击范围内 */ + inRangeOf?(from: Player, to: Player): boolean | void; + + /** + * 强制判断卡牌能否重铸 + * 【v1.9.108.6~】 + */ + cardChongzhuable?(card: Card, player: Player): boolean | void; + + aiValue?(player: Player, card: Card, num: number): number | void; + aiUseful?(player: Player, card: Card, num: number): number | void; +} + +/** 技能 */ +declare interface Skill { + /** + * 技能按钮名字,不写则默认为此技能的翻译(可认为为该技能用于显示的翻译名) + * 注:用得挺少得,貌似主要是使用翻译得 + */ + name?: string; + /** + * 新版:用于记录自身名字key,希望能用于自身某些配置上直接使用......,需要测试过才肯定;【结果:失败,还是没用,屏蔽掉】 + * + * 旧版:用于解析用的key,不直接参与游戏逻辑,参与自己定义的解析流程,实质就是技能的名字,规范按技能名命名 + */ + // key?:string; + + /** + * 继承 + * + * 比较特殊的属性,继承当前技能没有的,而inherit继承技能中有的属性; + * 其中“audio”属性,尽可能直接继承赋值为inherit的名字; + * 同时,对应的翻译会覆盖成继承技能的翻译。 + */ + inherit?: string; + + //声音 + /** + * 配音: + * + * 主要分为:audioname(默认技能名),audioinfo(默认info.audio) + * + * 若为字符串时,带有“ext:”,则使用无名杀录目\extension\扩展名内的配音(扩展的配音) + * + * ,命名方法:技能名+这是第几个配音 + * + * + * 否则,该字符串指代的是另一个技能的名字,若该技能名存在,则audioinfo为该技能的audio; + * + * 若为数组,则是[audioname,audioinfo],分布覆盖原有的值。 + * + * audioinfo为数字时,数字为配音数量索引(同一技能有多个配音),从1开始,使用无名杀目录\audio\skill内的配音(audioname1~audioinfo序号); + * + * audioinfo为布尔值true或者字符串非空时,执行game.playSkillAudio(audioname),使用无名杀目录\audio\skill内的配音; + * + * 否则,若为false,空字符串,null结果,则不播音, + * + * 若info.audio:true,则使用game.playSkillAudio(audioname)。 + * + * 扩展(以game.trySkillAudio为准): + * + * 若info.audio是字符串: + * + * 1.则主要是播放扩展声音,格式:ext:扩展包的名字:额外参数; + * + * 2.直接就是技能名,即继承该技能的播放信息,audioinfo; + * + * 若info.audio是数组,则[扩展名,额外参数]; + * + * 额外参数:1."true",则直接播放该名字的声音;2.数字,则是随机选一个该"技能名+1-数字范围"的声音播放; + * + * 若info.audio是数字,则直接就是用解析出来的"audioname+1-数字范围"; + */ + audio?: number | string | boolean | [string, number]; + /** + * 指定武将名的音频。 + * + * 强制使用该audioname覆盖上面解析出来的audioname,其解析出来的audioname为“audioname_玩家武将名”, + * + * 最终路径为:无名杀目录\audio\“audioname_玩家武将名” + * + * 扩展: + * 若info.audioname存在,且是数组,且方法参数有player,则播放"audioname_玩家名"的声音(即可同一个技能,不同人播放不同声音) + */ + audioname?: string[]; + //【v1.9.102】 + /** + * 添加audioname2机制,用于重定向特定角色的语音到特定技能 + * + * 其key值为人物的name; + */ + audioname2?: SMap; + /** 强制播放音频 */ + forceaudio?: boolean; + + + //时机与触发相关 + /** + * 触发的时机 + * + * 一般用于触发技能(被动技能) + * + * 注1:主动触发enable,是没有event._trigger; + * + * 注2:有trigger,就表示这是一个触发技能,触发技能必须要有触发内容“content”,没有会引发报错; + */ + trigger?: SkillTrigger; + + /** + * 为true时,将该技能加入到_hookTrigger + * + * 根据代码理解: + * + * 通过addSkillTrigger,挂载在player._hookTrigger中; + * + * 作为一个单独触发的方式,每次createTrigger,logSkill,filterTriggers时执行所有挂载在_hookTrigger所有对应的hookTrigger; + * + * 目前可知,其相关使用方法:after,block,log【目前只有于国战方法中,应该是作为全局执行方法的一种简约写法,实用不大】 + */ + hookTrigger?: HookTrigger; + + /** 同时机技能发动的优先度 */ + priority?: number; + + //基本都在核心createTrigger,addTrigger,trigger中逻辑触发相关,属于重要得属性 + /** + * 目前具体不知什么功能,当前所知,非常重要,和createTrigger,addTrigger,trigger相关 + * (推测,这属性是指明客户端是否显示该技能的操作按钮) + * + * 1.用于双将,若该设置不为true,该技能时在hiddenSkills隐藏技能列表中,且为“非明置”状态,结束当前“createTrigger”事件的触发; + * 即该设置,可以让隐藏技能触发; + * + * 2.用于event.addTrigger,event.trigger中,若该设置为true,默认为其priority+1,影响技能的触发顺序 + * (该顺序从代码看起来主要受priority影响,因为会*100,设置这个,会比其他同级优先一点) + * + * 3.当设置了该值为true, + * 若forced没设置到,则默认为true; + * 若popup没设置到,则默认为false; + * + * 故该设置核心功能:表明该技能是强行触发技能,并且不提示 + */ + silent?: boolean; + /** + * 目前具体不清楚什么功能,当前所知,也是个很重要得属性,估计是托管时是否触发得标记 + * + * 功能相当于forced+nopop ,会不会是被托管时的标记呢,正在验证 + * + * 用于双将,上面的silent为true,其非明置,该设置不为true,则触发“triggerHidden”; + * + * 功能好像是直接触发,在createTrigger中,直接event._result={bool:true}执行,否则可能需要(info.check进行ai检测); + */ + direct?: boolean; + /** + * 此技能是否可以被设置为自动发动(不询问) + * + * 设置了该属性的技能,可加入到配置选项中,自己设置是否自动发动(即该技能非必发技能) + * + * 若该属性值是“check”,则调用当前技能得check方法检测 + */ + frequent?: boolean | string | TwoParmFun; + /** + * 此技能是否可以被设置为自动发动2 + * + * 可以细分当前技能强制发动选项,(应该是为了细分子技能),保存到lib.config.autoskilllist, + * + * 在ui.click.autoskill2中执行, + * + * 取值为子技能的名字(注:目前,看来,只是在UI上作用,自动发动,更多是依赖frequent参数) + */ + subfrequent?: string[]; + /** + * 自动延迟的时间 + * + * 可以影响技能触发响应时间(主要影响loop之间的时间,即game.delayx的调用情况) + */ + autodelay?: boolean | number | TwoParmFun; + /** 第一时刻执行?(将发动顺序前置到列表前) */ + firstDo?: boolean; + /** 最后一刻做?(将发动顺序置于列表后方) */ + lastDo?: boolean; + + /** + * 此技能是否能固定触发(即自动发动)。 + * + * true为固定触发(可视为一种锁定技的,锁定技实质是mod里的技能) + * 国战可以触发亮将。 + * + * 【核心】作为game.check检测用的标准属性之一,在满足条件下强制执行。 + */ + forced?: boolean; + /** + * 死亡后是否可以发动技能 + */ + forceDie?: boolean; + /** + * 是否触发可以弹出选择技能的发动 + * + * 用于在arrangeTrigger过滤出多个同时机的触发技能时,在createTrigger中,询问玩家的技能发动, + * + * 若为false,不会加入询问触发的技能列表上(只有设置false才会); + * + * 若为字符串,则在createTrigger【step 3】触发技能时,使用player.popup弹出该提示文本; + */ + popup?: boolean | string; + /** + * player是否logSkill('此技能'). + * + * 设置true,则不弹出提示 + * + * 注:logSkill 则是在玩家确定要使用卡牌的情况下 弹出发动的技能(马里奥大佬的解释,到时看下) + * true为不 + */ + nopop?: boolean; + /** + * 取消触发后的处理 + * + * 在createTrigger中step 3处理 + * + * @param trigger + * @param player + */ + oncancel?(trigger: GameEventPromise, player: Player): void; + + //触发内容基本触发流程 + /** + * 在content之前执行 + * + * 在chooseToUse,step2中执行: + * 其执行时机和chooseButton一致,当chooseButton不存在时且game.online为false,则会执行这个 + * @param config + */ + precontent?: ContentFuncByAll; + /** + * 在content之前触发内容 + * + * 在useSkill中使用,主动触发技能content之前 + */ + contentBefore?: ContentFuncByAll; + /** + * 触发内容(技能内容) + * + * 作为被动触发技能: + * 在createTrigger,step3中创建当前技能的事件,设置该content为事件content作为触发内容; + * + * 作为主动触发技能: + * 在useSkill中创建当前技能的事件 + * 分步执行(通过step x分割开执行逻辑步骤) + * + * 注:此时的content,已经为触发该技能的效果而创建的,该技能执行中的事件,此时的event一般是不具备 + * 触发信息,触发的信息,主要在trigger触发事件中获取。 + */ + content?: ContentFuncByAll; + /** + * 在content之后触发内容 + * + * 在useSkill中使用,主动触发技能content之后 + */ + contentAfter?: ContentFuncByAll; + + //技能初始化与移除: + /** + * 获得技能时发动,初始化技能 + * + * 技能的话,则在addSkillTrigger,若第三个参数triggeronly取值为true,只设置触发,不初始化该技能; + * + * 正常在addSkill处理,this.addSkillTrigger(skill),使用此初始化; + */ + init?(player: Player, skill: string): void; + /** + * 添加技能时,初始化技能信息 + * + * 在addSkill中调用,每次添加都会执行 + */ + init2?(player: Player, skill: string): void; + /** 在执行player.disableSkill丧失技能时,若该属性为true,则执行技能的onremove */ + ondisable?: boolean; + /** + * 失去技能时发动 + * 当值为string时: + * + * 若为“storage”,删除player.storage中该技能的缓存(用于保存标记等信息); + * 注:失去这个技能时销毁标记。 + * + * 若为“discard”,若player.storage[skill]缓存的是卡牌时,执行game.cardsDiscard,并播放丢牌动画,然后移除player.storage[skill]; + * + * 若为“lose”,和“discard”差不多,不过不播丢牌动画; + * + * 当值为true时,直接移除player.storage[skill]; + * + * 当值为字符串集合时,则是删除集合中对应player.storage(即删除多个指定storage) + * + * 注:当前disableSkill中,若当前info.ondisable,调用onremove必须是方法,且不注入skill参数; + */ + onremove?: TwoParmFun | string | string[] | boolean; + /** 是否持续的附加技能,在removeSkill中使用 */ + keepSkill?: boolean; + + + //以下3个属性基本功能时一致:在某些模式下是否能使用,只使用一个就差不多 + /** + * 指定该技能在哪些模式下禁用 + * + * 注:在指定模式被禁用的技能,会被设置成空对象,并且“技能_info”的描述变成“此模式下不可用”。 + */ + forbid?: string[]; + /** 与forbid相反,只能在指定玩法模式下才能被使用,其他逻辑一致 */ + mode?: string[]; + /** 当前模式下是否能使用,返回false则不能使用,其实和forbid逻辑一致 */ + available?(mode: string): boolean; + + + //技能相关设置: + /** + * 技能组: + * + * 拥有这个技能时相当于拥有技能组内的技能 + * + * 注:一些特殊技能标签: + * + * “undist”:不计入距离的计算且不能使用牌且不是牌的合法目标 + * + * (被隔离玩家,目前确定的作用:player.getNext获取下一位玩家,player.getPrevious确定上一位玩家,player.distance计算玩家距离); + */ + group?: string | string[]; + /** + * 子技能: + * + * 你不会拥有写在这里面的技能,可以调用,可以用技能组联系起来; + * + * 子技能名字:“主技能_子技能”,翻译为主技能翻译 + * + * 注:子技能,会被视为“技能_子技能”独立保存起来。 + */ + subSkill?: SMap; + /** + * 全局技能?: + * + * 你拥有此技能时,所有角色拥有此技能(global的值为技能名) + * + * 注:无论是否拥有此技能,此技能都为全局技能写法:技能名前 + _ + */ + global?: string | string[]; + /** + * 在game.addGlobalSkill中使用: + * + * 强行设置global技能; + */ + globalSilent?: boolean; + + //技能相关设置=>功能设置 + /** + * 每回合限制使用次数 + * + * (若限制使用次数为变量时需写在filter内,即通过filter与变量动态判断) + * + * 主要在createTrigger,step3中触发计数。 + * + * 触发计数,会在玩家身上添加“counttrigger”技能,计数记录在:player.storage.counttrigger[当前技能名] + */ + usable?: number; + /** + * 每一轮的使用次数 + * + * 设置了该属性,会创建一个“技能名_roundcount”技能,将其加入group(技能组)中; + * + * 该技能的触发阶段“roundStart”(一轮的开始),用于记录当前技能的在一轮中使用的次数 + */ + round?: number; + /** 用于“技能名_roundcount”技能中,当前技能不可使用时,“n轮后”xxx,中xxx的部分显示(即后面部分) */ + roundtext?: string; + /** 增加显示的信息,这部分时增加,“n轮后”前面部分 */ + addintro?(storage: SMap, player: Player): string; + /** 延迟的时间 */ + delay?: number; + /** + * 锁定技 + * + * 若取值false,则get.is.locked,直接返回就false了; + * + * (锁定技的判定:1.info.trigger&&info.forced;2.info.mod;3.info.locked) + * + * 是否可以被“封印”(内置技能“fengyin”)的技能,取值为false时,get.is.locked返回为false;true则正常逻辑 + */ + locked?: boolean; + /** 是否是旧版技能,值为true,添加到lib.config.vintageSkills中,可以实现新/旧版技能切换,如果该为true,则“原翻译名_alter”即作为当前的翻译 */ + alter?: boolean; + + + //锁定技 + /** + * mod技能的设置 + * + * 如果有,技能视为锁定技 + * */ + mod?: Mod; + + //【重点】标记的key需要和技能名一致,游戏内都是通过对应skill取得对应的标记key,即player.storage[skill] + //限定技与觉醒技与技能标记 + /* + 关于限定技规范: + 一般情况下,需要在filter中,可加入!player.storage.xxx==true判定, + 在发动后,content内设置player.storage.xxx=true,代表已经触发了; + 目前,可以采用另一种简洁的方法,即觉醒技方法: + player.awakenSkill("xxx"); + 这样就会屏蔽发动过的技能,不会发动第二次; + */ + + /** + * 限定技(标记) + * + * 该标记为true时,若没有设置以下内容,则会自动设置: + * + * mark设置为true; + * + * intro.content设置为“limited”; + * + * skillAnimation设置为true; + * + * init设置为初始化玩家缓存的该技能名标记为false; + */ + limited?: boolean; + /** + * 是否开启觉醒动画 + * + * 准备来说,常用于觉醒动画,实际是指技能动画 + * + * 字符串时取值:epic,legend + */ + skillAnimation?: boolean | string; + /** 是否只显示文字特效 */ + textAnimation?: boolean; + /** 动画文字(可用于觉醒文字) */ + animationStr?: string; + /** 动画文字颜色(觉醒文字颜色) */ + animationColor?: string; + /** + * 觉醒技标记: + * + * (目前来看,这个目前单纯是技能标记,在主逻辑上并没使用,但貌似会被某些技能本身用到,或者类似左慈判断不能获得的技能的) + */ + juexingji?: boolean; + /** + * 获得技能时是否显示此标记, + * + * 若为false,可以用 markSkill 来显示此标记, + * + * 可以用 unmarkSkill 不显示标记 + * + * mark的常量值:"card","cards","image","character",表示,标记显示的特殊形式(UI上) + * + * 注:character,只能在表示一个角色时使用,标记以角色牌形式显示; + * + * 注:取值“auto”,在updateMark时,有计数时,执行unmarkSkill(?????) + */ + mark?: boolean | string; + /** 标记显示文本,一般为一个字 */ + marktext?: string; + /** 标记显示内容 */ + intro?: { + /** 自定义mark弹窗的显示内容 */ + mark?: ThreeParmFun; + /** 用于info.mark为“character”,添加,移除标记时,log显示的标记名(好像意义不大) */ + name?: string | TwoParmFun; + /** + * 标记显示内容? + * 为cards时显示标记内的牌. + * + * 当标记显示内容是文本: + * + * "mark":有(数)个标记; + * + * "card":一张牌; + * + * "cards":多张牌; + * + * "limited":限定技,觉醒技专用;(若没设置,在info.limited为true下回默认设置这个) + * + * "time":剩余发动次数; + * + * "turn":剩余回合数; + * + * "cardCount":牌数; + * + * "info":技能描述; + * + * "character":武将牌; + * + * "player":一个玩家; + * + * "players":多个玩家; + * + * 可以只是一个描述文本; + * + * 在get.storageintro 中使用,以上,即为该方法的type,返回标记的描述内容 + * + * 若info.mark为“character”,则一般为一个描述文本; + * + * 注:info.mark为true时,也可以使用文本描述,比较自由(按道理都可以,不过默认搭配而已); + * + * 其中,文本可使用以下占位符: + * + * "#":(this.storage[skill])获取对应的计数, + * + * "&":get.cnNumber(this.storage[skill])获取对应的计数(需要使用到get.cnNumber来获取的数量), + * + * "$":get.translation(this.storage[skill])获取对应描述(一般是描述的角色名) + * + * 也可以是个自定义的方法 + */ + content?: string | ThreeParmFun; + /** + * 标记数 + * + * 主要在player.updateMark时使用,实际顶替this.storage[i+'_markcount']获取标记数 + */ + markcount?: number | TwoParmFun | string; + /** 是否不启用技能标记计数 */ + nocount?: boolean; + /** + * 移除该标记时,在unmarkSkill执行 + * + * 若值为字符串“throw”,该玩家缓存中该技能标记的为牌时,播放丢牌动画; + * + * 若是方法,则直接使用该回调方法处理。 + * + * 注:该参数原本只在把整个标记移除时执行,后续可能自己扩展; + */ + onunmark?: TwoParmFun | string; + // id?:string; //id名字需带“subplayer”,用于特殊模式显示信息用 + }; + + //主公技 + /** + * 是否为主公技: + * + * true时,将这个技能设置为主公技 + * + * (目前来看,这个目前单纯是技能标记,在主逻辑上并没使用,但貌似会被某些技能本身用到) + */ + zhuSkill?: boolean; + + //主动技能(主动使用技能,包含技能使用的相关操作配置) + /** + * 可使用的阶段 + * + * 一般用于主动技能 + * + * 注:从这个info.enable==event.name看出,其实和trigger差不多,所有事件的发动都会阶段时点; + * + * 即,当前执行的事件,触发game.check,时,检测触发的技能的event.name,即是info.enable; + * + * 常用的阶段: + * + * phaseUse:出牌阶段使用; + * + * chooseToRespond:用以响应; + * + * chooseToUse:常用于“濒死使用”/打出使用 + */ + enable?: string | string[] | OneParmFun; + /** + * 是否显示弹出该技能使用卡牌的文字 + * + * useCard中使用, + * + * 若为true的话,则执行player.popup + * + * 例如:player.popup({使用卡牌名name,使用卡牌nature},'metal') + */ + popname?: boolean; + + //视为技(转换卡牌的技能) + /** + * (视为)目标卡牌 + * + * 一般用于视为技能 + * + * 【v1.9.102】扩展:可以使用函数式viewAs,目前核心支持使用地方:backup,ok; + */ + viewAs?: string | CardBaseUIData | TwoParmFun; + /** + * 视为技按钮出现条件(即发动条件) + * @param player + */ + viewAsFilter?(player: Player): boolean | void; + /** + * 使用视为牌时触发内容。 + * + * result.cards是视为前的牌 + * + * 注:实际是useResult,若当前处理的是技能,则先触发这个,后面再更具具体情况执行useCard,useSkill; + * + * 一般是用于视为技作为,效果处理,作为其他处理,会显得多余,算是视为技的扩展操作 + * + * @param result + * @param player + */ + onuse?(result: BaseCommonResultData, player: Player): void; + /** + * 选择按钮(牌) + * + * 常用于视为技需要实现复杂的功能选项时使用; + * + * 当前使用范围: + * + * chooseToUse + * + * chooseToRespond + */ + chooseButton?: ChooseButtonConfigData; + /** + * 源技能 + * + * (该属性应该是动态生成的,用于记录执行backup的技能名,即执行backup的视为技能,实质是执行本技能) + * + * 在chooseToUse,step1中使用,若有,将器添加到event._aiexclude中; + * + * + * 目前来看,该字段不是配置进去的,而是chooseToUse,step3中,执行chooseButton的backup方法, + * + * 返回一个新的“视为”技能:“技能名_backup”,并设置到lib.skill中, + * + * 并且将技能名作为该技能的源技能设置到这个新技能的sourceSkill中。 + */ + sourceSkill?: string; + + + //具体功能的处理 + //弃牌,失去牌(默认不设置discard,lose,则直接player.discard弃置选择的牌) + //discard,lose其中一个false,都会为非视为技走lose事件失去卡牌,且提供丰富的参数设置; + /** + * 是否弃牌 + * + * 在useSkill中调用, + * + * 选择牌发动技能后,被选择的牌都要弃置 + * + * 取值false(因为undefined != false结果为true,故默认不填和true效果一致) + */ + discard?: boolean; + /** + * 是否失去牌(是否调用player.lose) + * + * 与discard调用时机一致,都在useSkill中, + * 取值为false + */ + lose?: boolean; + /** + * 不弃牌,准备用这些牌来干什么(用于播放动画) + * + * 其字符串枚举有: + * + * give,give2,throw,throw2 + * + * 若不是字符串,则执行该方法 + */ + prepare?: string | ThreeParmFun; + /** 在lose事件中使用,触发执行“lose_卡牌名”事件的content */ + onLose?: ContentFunc | ContentFunc[]; + /** + * 在lose事件中使用,必须要失去的卡牌为“equips”(装备牌),有onLose才生效。 + * 若符合以上条件,则检测该牌是否需要后续触发执行“lose_卡牌名”事件,既上面配置的onLose + */ + filterLose?: TwoParmFun; + /** 在lose事件中使用,取值为true,作用貌似强制延迟弃牌动画处理 */ + loseDelay?: boolean; + + /** + * 是否触发lose失去牌阶段 + * + * 取值false; + * + * 若为false,则跳过该触发 + * + * 适合lose绑定一起使用,为false时,设置丢失牌事件_triggered为null + */ + //新版本出牌阶段主动技的新参数(均仅在discard为false且lose不为false时有效),且losetrigger不为false, + //是默认情况下:执行player.lose(cards,ui.special),以下为 + losetrigger?: boolean; + /** 让角色失去卡牌的过程中强制视为正面朝上失去(losetrigger不为false时,既默认情况下生效) */ + visible?: boolean; + /** + * 指定失去特殊区卡牌的去向 (即设置卡牌的position) + * + * 其值采用的是ui的成员,即通过ui[info.loseTo],获取实体对象设置; + * + * 默认为:"special", + * + * 取值:"special","discardPile","cardPile","ordering","control"(这一般都不会用上,好像没看见) + */ + loseTo?: string; + /** + * 需要失去的牌的区域ui.special(默认情况是这个,受loseTo影响), + * + * 设置lose事件的toStorage为true,失去的牌到牌记录到自己的storage中; + */ + toStorage?: boolean; + /** + * 用于将失去的牌置于某个区域的顶端(而非默认的顶端);【v1.9.108.6】 + */ + insert?: boolean; + + /** + * 技能响应前处理(非联机时,不在线时处理,估计时用于自动响应) + * + * 在chooseToRespond中使用 + */ + prerespond?(result, player: Player): void; + /** + * 技能响应(可直接使用技能来响应,在这里进行响应的处理) + * + * 在respond中使用 + */ + onrespond?(event: GameEventPromise, player: Player): void; + /** + * 过滤发动条件,返回true则可以发动此技能 + * + * 主要在filterTrigger,game.check中处理,返回false则不处理(可以不设置该配置,相当于默认true结果) + * + * 注: + * + * 1.主动触发:一般走的是game.check,其filter,传入的event指的是当前game.check处理的事件; + * + * 2.被动触发:一般走的是lib.filter.filterTrigger,其filter,传入的event指的是当前的触发事件,其中还会把触发事件名传入第三个参数; + * @param event 事件,即event._trigger,相当于trigger时机(此时的event为触发该技能时机时的事件) + * @param player + * @param name 触发名,为event.triggername,目前只有在lib.filter.filterTrigger中才传该值,即被动触发,主动触发不检测该值,目前暂未完善 + */ + filter?(event: GameEventPromise, player: Player, name?: string): boolean | void; + /** + * 选择的目标武将牌上出现什么字。 + * + * 使用地方:ui.click.target/player,.... + * + * 如果是数组第几元素对应第几个目标; + * + * 如果是方法,则直接根据入参target,判断返回的文本; + * + * 例子: + * targetprompt:['出杀','出闪'],依次就是你点击第一个角色后在其旁边显示出杀,第二个角色显示出闪 + */ + targetprompt?: string | string[] | OneParmFun; + /** + * 是否每个目标都结算一次(多个目标) + * + * true为可选择多名目标 + */ + multitarget?: boolean | number; + /** + * 指向线的颜色枚举: + * fire(橙红色FF9244),thunder(浅蓝色8DD8FF),green(青色8DFFD8), + */ + line?: string | { color: number[] }; + /** 是否显示多条指引线 */ + multiline?: boolean; + + /** + * 选中该技能使用时,进行处理 + * + * 在chooseToUse 的content中调用, + * + * 目前参考的例子中,大多数多是用于添加一些牌到待选择到event.set(key,收集的牌)中, + * + * 用于使用前先选牌的效果 + * + * 注:其调用时机应该远早于触发技能的,在选中牌时就开始处理。 + * @param event + */ + onChooseToUse?(event: GameEventPromise): void; + + /** + * 改变拼点用的牌 + * + * 在chooseToCompare和chooseToCompareMultiple,step2中使用,返回玩家用于的拼点的牌 + * @param player + */ + onCompare?(player: Player): Card[]; + + /** + * 在chooseToRespond时使用,会前置执行当前chooseToRespond事件player所有的技能该接口; + * + * 应该时用于chooseToRespond事件时,技能进行一些初始化处理(暂无使用实例) + * 【v1.9.106】 + * @param event + */ + onChooseToRespond?(event: GameEventPromise): void; + + //核心 + //event.bakcup设置的信息,game.check使用到的一些参数,其实就是把game.check需要的一些参数设置到技能中,作为check时的条件 + // 追加:这个主要用于game.check检测中,取代当前事件的条件;若没有主动申请检测,则其实用不上; + // 在表现上,主要用于:主动技,视为技 + /* 这些就是作为前提条件的主要属性 + filterButton + selectButton + filterTarget + selectTarget + filterCard + selectCard + position + forced + complexSelect?:boolean; + complexCard?:boolean; + complexTarget + ai1 + ai2 + */ + //目标 + /** + * 需要选择多少张牌才能发动 + * + * 选择的牌数 + * + * -1时,选择所有牌,否则就是指定数量的牌 + * + * 数组时,这个数组就是选择牌数的区间,其中任意(至少一张):[1,Infinity] + * + * 为变量时(具体情况具体分析),例:()=>number + */ + selectCard?: number | Select | NoneParmFum; + /** + * 需要选择多少个目标才能发动 + * + * 选择的目标数: + * + * 为-1时,选择全部人 + * + * 为数组时,这个数组就是选择目标数的区间 + */ + selectTarget?: number | Select | NoneParmFum; + /** + * 选择的牌需要满足的条件 + * + * 可以使用键值对的简便写法 + * + * 也可以使用函数返回值(推荐) + * + * 都是通过get.filter处理成事件的filterCard的方法; + * + * 直接填true,则有些地方,会优先触发过滤可使用的卡牌,例如ui.click.skill,ai.basic.chooseCard + * + * 注:game.check时,如果当前时viewAs“视为技”,则其过滤技能时filterCard,作为方法,多入参一个event参数,需要时可以使用; + * (一般没有) + */ + filterCard?: boolean | CardBaseUIData | TwoParmFun | boolean; + /** + * 是否使用mod检测 + * + * 取值true; + * + * 在event.backup使用, + * + * 当info.viewAs有值的时候(即该技能为视为技), + * + * 若没有设置filterCard,默认设置一个filterCard: + * 可以优先使用“cardEnabled2”的mod检测卡牌是否可使用; + * + * + * 已找不到,可能就是改成cardEnabled2 + * + * 则若当前事件为”chooseToUse“(选择卡牌使用),使用”cardEnabled“卡牌是否能使用mod检测; + * + * 则若当前事件为”chooseToRespond“(选择卡牌响应),使用”cardRespondable“卡牌是否能响应mod检测; + */ + ignoreMod?: boolean; + /** + * 选择的目标需要满足的条件 + * @param card + * @param player + * @param target + */ + filterTarget?(card: Card, player: Player, target: Player): boolean; + /** + * 指定位置: + * 'h':手牌区, 'e':装备区, 'j':判定区 + */ + position?: string; + /** + * 选择时弹出的提示 + * + * 单参数的方法,主要用再技能点击使用时的提示; + * + * 注:即触发技能/主动发动技能的提示描述信息; + */ + prompt?: string | TwoParmFun; + //| TwoParmFun | TwoParmFun //好像没见到用 + /** + * 二次提示 + * + * 主要在createTrigger,step1中,设置event.prompt2 + * + * 若是boolean类型,则取值false,不显示prompt2,默认使用lib.translate[“技能名_info”]的描述 + * + * 注:即发动技能时,prompt提示下的提示(默认显示技能描述); + */ + prompt2?: string | TwoParmFun | boolean; + /** + * 在ui.click.skill中使用,若当前event.skillDialog不存在,可以用该方法生成的文本的dialog作为skillDialog; + * + * 若没有该方法,可以使用翻译中该技能的info信息代替。 + */ + promptfunc?: TwoParmFun; + /** 表示这次描述非常长(涉及用了h5文本),设置为true,重新执行ui.update(),设置skillDialog.forcebutton为true */ + longprompt?: boolean; + + //补充game.check相关参数的声明: + /** 过滤不可选择按钮 */ + filterButton?(button: Button, player: Player): boolean; + /** 按钮的可选数量,大多数情况下,默认1 */ + selectButton?: number | Select | NoneParmFum; + complexSelect?: boolean; + /** 复合选牌:即每选完一次牌后,都会重新下一次对所有牌的过滤 */ + complexCard?: boolean; + complexTarget?: boolean; + + /** 一般作为chooseCard相关ai */ + ai1?: Function; + /** 一般作为chooseTarget相关ai */ + ai2?: Function; + + /** + * 是否检测隐藏的卡牌 + * + * 使用范围:player.hasUsableCard,player.hasWuxie + * + * 常用:让系统知道玩家“有无懈”; + * + * 例子:可以参考“muniu”(木牛流马) + * @param player + * @param name + */ + hiddenCard?(player: Player, name: string): boolean; + + /** 录像相关,game.videoContent.skill中相关 */ + video?(player: Player, data: string | any[]): void; + + process?(player: Player): void; + + //在skillDisabled中,根据以下5个属性,检测技能是否是不能使用(若其中有一个时true都排除掉),在chooseSkill,选择获得技能时筛选列表 + //在getStockSkills中,有前3个标签属性的技能也是无法获取的 + /** + * 唯一 + * + * 在skillintro中使用(左慈不能化身) + * + * 注:该技能是否为特殊技能,即左慈化身能否获取等等,常与部分锁定技、主公技、觉醒技连用 + */ + unique?: boolean; + /** 临时技能,在die死亡时,会被移除 */ + temp?: boolean; + /** 子技能标签,在subSkill的技能中,会默认标记该属性为true */ + sub?: boolean; + /** 固有技,不能被removeSkill移除 */ + fixed?: boolean; + /** 一次性技能,在resetSkills时,直接移除该技能 */ + vanish?: boolean; + + /** + * 武将特有固有技能 + * + * 从逻辑上来看,比固定技优先级还高,不会受“fengyin”,“baiban”等技能移除; + * + * 在clearSkills时,如果不是“删除所有的all为true”的情况下,不会被移除; + * + * 不会被,“化身”之类的技能获得,删除; + */ + charlotte?: boolean; + /** 在clearSkills中使用,标记此标记,永远不会被该方法删除,该标记独立使用,一般其他方法没有对其进行处理 */ + superCharlotte?: boolean; + /** 作用不明,并没有什么用,与ui相关,在skillintro中使用,值为true */ + gainable?: boolean; + /** 在nodeintro中使用,添加classname:thundertext,值为true */ + thundertext?: boolean; + + //在nodeintro中使用的(这几个配置都没什么意义) + /** 设置nodeintro的点击事件 */ + clickable?(player: Player): void; + /** 过滤点击,应该是过滤弹出面板是否能点击,具体作用日后细究 */ + clickableFilter?(player: Player): boolean; + /** 技能名不带【】括号 */ + nobracket?: boolean; + + //日志相关: + /** 是否在历史日志中显示,取值未false不显示 */ + logv?: boolean; + /** + * 显示场上日志中显示 + * + * 在useSkill时,若值为“notarget”,则不显示出对所有“对...”目标相关描述的日志; + * + * 在useCard时,若该设置未false,则不执行player.logSkill; + */ + log?: boolean | string; + /** + * 目标日志 + * + * 若是字符串,则配置一个当前处理的trigger事件的一个玩家元素,例如"player","source","target"...; + * + * 若是方法,则配置一个方法直接返回文本,或者玩家 + * + * 若没有配置prompt,显示该配置的提示 + */ + logTarget?: string | TwoParmFun; + /** + * 是否通过logTarget显示触发者的目标日志; + * + * 目的:应该是为了细节化显示日志;在createTrigger,step3中使用,取值false,不使用logTarget,显示logSkill; + */ + logLine?: boolean; + + //技能的信息显示: + /** + * 内容描述 + * + * 在addCard时,设置“技能名_info”的翻译;(addCard很少使用) + * + * 若时subSkill子技能,则设置“技能名_子技能名_info”的翻译;(主要适用于子技能描述) + * + * 该技能的描述(自定义,非子技能时和game逻辑无关,用于自己的解析逻辑) + */ + description?: string; + /** 该技能的描述(自定义,和game逻辑无关,用于自己的解析逻辑) */ + // infoDescription?:string; + /** + * 来源: + * + * 若该来源技能不存在,则当前技能会被移除; + */ + derivation?: string[] | string; + + /** + * 强制加载该card配置, + * 例如,一些原本不用于contect模式得卡,设置该值可强制加载该card + */ + forceLoad?: boolean; + + //AI相关 + /** ai的详细配置 */ + ai?: SkillAI; + + /** + * ai用于检测的方法: + * + * 第一个参数好想有些不一样:event,card,子技能button; + * + * 基本ai.basic使用的check方法(既涉及choose系列时用的ai自动选择): + * + * 1)ai如何选牌: + * + * 在ai.basic.chooseCard中使用; + * + * 2)ai如何选按钮: + * + * 在ai.basic.chooseButton中使用; + * + * 3)ai如何选玩家: + * + * 在ai.basic.chooseTarget中使用; + * + * 注:其实这些应该都有两个参数的,既第二个参数其实当前所有选中的的数据; + * + * 有时甚至不传参,所以遇到保存,做好健壮性屏蔽; + * + * 特殊作用: + * + * 在触发createTrigger中使用,参数:trigger事件,player玩家; + * + * 1)在技能过滤触发时作为过滤条件(当前技能info.frequent=='check'): + * + * 2)告诉ai是否发动这个技能:返回true则发动此技能,即作为createTrigger过程中,设置ai如何chooseBool这个技能; + * + * 例: + * + * a.触发技判断敌友,大于0为选择队友发动,若<=0是对敌方发动:return get.attitude(player,event.player)>0; + * + * b.选取价值小于8的牌:return 8-get.value(card); 数字越大,会选用的牌范围越广,8以上甚至会选用桃发动技能,一般为6-ai.get.value(card); + * + * 注: + * + * 两个参数,用于事件触发技能:event:GameEvent,player:Player; + * + * 一个参数,用于主动使用触发技能:card:Card; + * + * 无参,简洁写法; + */ + check?: OneParmFun | TwoParmFun | NoneParmFum; + // check?(...any:any):number|boolean; + // /** ai用于检测的方法:用于主动使用触发技能 */ + // check?(card:Card):number|boolean; + // /** ai用于检测的方法:用于事件触发技能 */ + // check?(event:GameEventPromise,player:Player):number|boolean; + // check?():number|boolean; + // check?:OneParmFun | OneParmFun | OneParmFun | TwoParmFun; + + //event.addTrigger,默认对于技能优先度的标记:rule; + /** + * 发动技能是身份暴露度(0~1,相当于概率) + * 取值范围为0~1,用于帮助AI判断身份,AI中未写expose其他AI将会无法判断其身份 + */ + expose?: number; + /** + * 嘲讽值: + * 嘲讽值越大的角色越容易遭受到敌方的攻击,默认为1,一般在0~4中取值即可(缔盟threaten值为3) + */ + threaten?: number | TwoParmFun; + /** + * 态度: + * 态度只由identity决定。不同身份对不同身份的att不同。 + * 例如:在身份局中,主对忠att值为6,忠对主att值为10; + * 注:配置不配该值; + */ + // attitude?: number; + + /** + * 效果: + * 影响ai出牌(例如什么时候不出杀)等 + * 效果值为正代表正效果,反之为负效果,AI会倾向于最大效果的目标/卡牌; + * + * 告诉ai有某技能时某牌的使用效果发生改变。 + * + * ai里面的effect是上帝视角,target不代表目标角色,player也不代表拥有此技能的玩家本身, + 因为effect是写给别的AI看的,所以target代表玩家本身,player代表其他人,可以是正在犹豫是否要杀你的任何一位玩家。 + + * 注:若不是个对象,可以直接是一个target(一种简写形式,不收录了) + * + * 应用: + * 〖主动技〗 + 如果技能发动无须指定目标: effect=result*ai.get.attitude(player,player); + 如果技能发动须指定目标 总效果=对使用者的收益值 * 使用者对自己的att+对目标的收益值 * 使用者对目标的att; 实际还会考虑嘲讽值,这里简化了; + 〖卖血技〗 + 总效果=对使用者的收益值 * 使用者对自己的att+对目标的收益值 * 使用者对目标的att; 实际还会考虑嘲讽值,这里简化了; + + 设对目标的原收益为n,对使用者的原收益为n',n>0代表正收益,n<0代表负收益; + 函数传入4个参数,分别为卡牌、使用者、目标以及n; + 返回值可有3种形式 + 1. 一个数a,对目标总的收益为a*n; + 2. 一个长度为2的数组[a,b],对目标的总收益为a*n+b; + 3. 一个长度为4的数组[a,b,c,d],对目标的总收益为a*n+b,对使用者的总收益为c*n'+d; + 假设n代表火杀对目标的效果 + 1. 技能为防止火焰伤害:return 0; + 2. 技能为防止火焰伤害并令目标摸一张牌:return [0,1]; + 3. 技能为防止火焰伤害并令使用者弃置一张牌:return [0,0,1,-1]; + + 〖倾向技〗 + 对确定的意向,反应准确的收益 + + 【收益论的检验】示例: + content:function(){ + game.log(player,'对',target,'的att是',ai.get.attitude(player,target)); + game.log(player,'对',player,'的att是',ai.get.attitude(player,player)); + game.log(player,'对',target,'发动【测试】的eff是',ai.get.effect(target,'测试',player,player)); + game.log(player,'对',target,'使用【杀】的eff是',ai.get.effect(target,{name:'sha'},player,player)); + }, + + 永远的萌新大佬的示例: + effect的返回值: + effect有3种可能的返回值,1个数字,长度为2的数组,长度为4的数组。 + 1个数字n:收益*n + 长度为2的数组[a,b]:a*收益+b + 长度为4的数组[a,b,c,d]:对目标为a*收益+b,对使用者为c*收益+d + *注意 zeroplayertarget 实际上是[0,0,0,0] zerotarget 实际上是[0,0 + "下面以target:function(){},别人对你使用杀为例,括号里为可能的技能描述" + return -1;//负影响(杀对你造成伤害时改为等量回复) + return 0;//无影响(杀对你无效) + return 2;//2倍影响(杀对你的伤害翻倍) + return 0.5;//一半影响(杀对你的伤害减半) + return [1,1];//正常影响+1(成为杀的目标摸一张牌) + return [1,-1];//正常影响-1(成为杀的目标弃一张牌) + return [0,1];//无影响+1(杀对你造成伤害时改为摸一张牌); + return [0,-1];//无影响-1(杀对你造成伤害时改为弃一张牌) + return [1,0,0,-1];//对你正常影响,对使用者无影响-1(刚烈) + return [1,1,1,1];//对双方正常影响+1(你成为杀的目标时你和使用者各摸一张牌) + */ + effect?: { + /** + * 牌对你的影响(你使用牌/技能对目标的影响) + * + * 返回结果的字符串:"zeroplayer","zerotarget","zeroplayertarget",指定最终结果的:对使用者的收益值,对目标的收益值为0 + * @param result1 即当前ai.result.player的结果 + */ + player?(card: Card, player: Player, target: Player, result1: number): string | number | number[] | void; + /** + * 一名角色以你为牌的目标时对你的影响(牌/技能对你的影响) + * + * 返回结果的字符串:"zeroplayer","zerotarget","zeroplayertarget",指定最终结果的:对使用者的收益值,对目标的收益值为0 + * @param result2 即当前ai.result.target的结果 + */ + target?(card: Card, player: Player, target: Player, result2: number): string | number | number[] | void; + }; + /** + * 收益: + * 收益值未在AI声明默认为0(对玩家对目标均是如此)。 + * 一般用于主动技; + * 关于收益的算法,待会再详细描述 + * + * 在get.result中使用; + * + */ + result?: { + /** + * ai如何选择目标(对目标的收益): + * 返回负,选敌人,返回正,选队友; + * 没有返回值则不选; + * 注:写了这个就不用写player(player){}了,因为player可以在这里进行判断......先继续研究好,再下定论; + */ + target?: ThreeParmFun | number; + /** + * 主要用于get.effect_use中,优先于上面的target; + */ + target_use?: ThreeParmFun | number; + /** + * ai是否发动此技能(对玩家(自身)的收益): + * 返回正,发动,否则不发动; + * 注:最终 + */ + player?: ThreeParmFun | number; + /** + * 主要用于get.effect_use中,优先于上面的player; + */ + player_use?: ThreeParmFun | number; + + /** + * 取值为true时,不默认为“equip(装备)”卡牌,默认设置“card.ai.result.target”方法 + */ + keepAI?: boolean, + } + /** + * 技能标签的生效限制条件 + * + * 例:视为技中使用,ai什么时候可以发动视为技(决定某些技能标签的true/false) + * 在player.hasSkillTag,player.hasGlobalTag中使用 + */ + skillTagFilter?(player: Player, tag: string, arg: any): boolean | void; + + //------------------------------主要给卡牌使用的ai配置(也共享上面一些配置)-------------------------------- + //若武将使用以下配置,一般为该武将的“视为技”时使用,其配置对应“视为”的卡牌 + + //这些时在外的简写,一般详细处理,在basic内 + /** + * 回合外留牌的价值【一般用于卡牌的ai】 + * + * 大致的价值标准: + * tao [8,6.5,5,4]>shan [7,2]>wuxie [6,4]>sha,nanman [5,1]>wuzhong 4.5>shunshou,tiesuo 4 + * wugu,wanjian,juedou,guohe,jiedao,lebu,huogong,bingliang 1>shandian 0 + * 注:当value的结果为一个数组时,则标识当前card在手牌中位置,根据该牌所处位置,获得对应下标不同的value; + */ + useful?: number; + /** + * 牌的使用价值【一般用于卡牌的ai】 + * + * 数字越大,在一些ai会选用的牌范围越广,8以上甚至会选用桃发动技能,一般为6-ai.get.value(card); + * 大致的价值标准: + * wuzhong 9.2>shunshou 9>lebu 8>tao [8,6.5,5,4]>shan [7,2]>wuxie [6,4]>juedou 5.5>guohe,nanman,wanjian 5>sha [5,1] + * tiesuo,bingliang 4>huogong [3,1]>jiedao 2>taoyuan,shandian 0 + * 注:当value的结果为一个数组时,则标识当前card在手牌中位置,根据该牌所处位置,获得对应下标不同的value; + */ + value?: number | number[] | TwoParmFun; + /** 该装备的价值 */ + equipValue?: number | TwoParmFun; + /** 主要是使用在card的ai属性,武将技能可以无视 */ + basic?: { + /** 该装备的价值,同equipValue,优先使用equipValue,没有则ai.basic.equipValue */ + equipValue?: number | TwoParmFun; + /** 优先度 */ + order?: number | TwoParmFun; + /** 回合外留牌的价值(该牌可用价值),number为当前事件玩家的手牌的下标 */ + useful?: SAAType | TwoParmFun>; + /** 该牌的使用价值 */ + value?: SAAType | FourParmFun>; + + [key: string]: SAAType | string | Function; + }; + + //ai的tag【可用于标记卡牌的属性】 + //get.tag(卡牌,标签名) 检测是否有指定卡牌标签: + /** 主要是使用在card中,独立制定的一些标记来描述自身得一些特性,有则标记1,默认是没有(实质上用bool也行),可能有少许标记参与运算 */ + tag?: { + //比较常用:(以下为自己得理解) + /** 【响应杀】:即手上没有杀时,也有可能响应杀 */ + respondSha?: CardTagType; + /** 【响应闪】:即手上没有闪时,也有可能响应闪 */ + respondShan?: CardTagType; + /** 【不会受到伤害】 */ + damage?: CardTagType; + /** 【不受元素伤害】 */ + natureDamage?: CardTagType; + /** 【不受雷属性伤害】 */ + thunderDamage?: CardTagType; + /** 【不受冰属性伤害】【v1.9.107】 */ + iceDamage?: CardTagType; + /** 【不受火属性伤害】 */ + fireDamage?: CardTagType; + /** 【可以指定多个目标】 */ + multitarget?: CardTagType; + /** 【回复体力】 */ + recover?: CardTagType; + /** 【失去体力】 */ + loseHp?: CardTagType; + /** 【可获得牌】 */ + gain?: CardTagType; + /** 【可自救】 */ + save?: CardTagType; + /** 【可弃牌】,即弃牌可以有收益 */ + discard?: CardTagType; + /** 【失去牌】 */ + loseCard?: CardTagType; + /** 【多个目标结算时(?存疑)】 */ + multineg?: CardTagType; + /** 【可多次/再次判定/改变判定】 */ + rejudge?: CardTagType; + draw?: CardTagType; + norepeat?: CardTagType; + /** 【装备替换价值】 */ + valueswap?: CardTagType; + + [key: string]: CardTagType; + } + + /** + * 是否要对“连锁”状态下的目标处理; + * + * 新增,在get.effect中使用; + * @param player + * @param target + * @param card + */ + canLink?(player: Player, target: Player, card: Card): boolean; + + //日后还有很多属性要添加的 + [key: string]: any; +} + +/** 卡牌的tag的类型,注:作为方法的第二参数很少用上(一般用于二级类型判断) */ +type CardTagType = number | TwoParmFun | OneParmFun; \ No newline at end of file diff --git a/node_modules/noname-typings/index.d.ts b/node_modules/noname-typings/index.d.ts index 0fb50a1c1..404fc9e56 100644 --- a/node_modules/noname-typings/index.d.ts +++ b/node_modules/noname-typings/index.d.ts @@ -1,8 +1,11 @@ /// +/// /// /// /// /// +/// +/// /// /// /// diff --git a/node_modules/noname-typings/package.json b/node_modules/noname-typings/package.json index 9ee543937..db42e298b 100644 --- a/node_modules/noname-typings/package.json +++ b/node_modules/noname-typings/package.json @@ -1,6 +1,6 @@ { "name": "noname-typings", - "version": "2023.12.31", + "version": "2024.01.16", "description": "Noname typings, mainly for showing type hints when creating extensions of the Sanguosha-like game Noname.", "repository": { "type": "git", diff --git a/node_modules/noname-typings/type.d.ts b/node_modules/noname-typings/type.d.ts index 2ca05dbe7..2ef629b1f 100644 --- a/node_modules/noname-typings/type.d.ts +++ b/node_modules/noname-typings/type.d.ts @@ -17,15 +17,43 @@ interface NMap { [key: number]: V } -declare type Game = import('../../noname/game/index.js').Game; -declare type Library = import('../../noname/library/index.js').Library; +//从0个参数到任意参数的方法结构声明 +type NoneParmFum = () => T; +type OneParmFun = (arg0: U) => T; +type TwoParmFun = (arg0: U1, arg1: U2) => T; +type ThreeParmFun = (arg0: U1, arg1: U2, arg2: U3) => T; +type FourParmFun = (arg0: U1, arg1: U2, arg2: U3, arg3: U4) => T; +type RestParmFun = (...args) => T; +type RestParmFun2 = (...args: U[]) => T; + +//尝试增加的符合类型声明 +/** SingleAndArrayType:单体与集合类型 */ +type SAAType = T | T[]; +/** 再价格可以返回这种类型的方法 */ +type SAAFType = T | T[] | RestParmFun; +/** 有name属性的对象 */ +type NameType = { name: string }; +/** 技能或者卡牌 */ +type SkillOrCard = string | NameType | Card; +/** 卡牌或者卡牌集合 */ +type CCards = SAAType; + +/** 技能content */ +declare type ContentFuncByAll = { + // (event: GameEventPromise, step: number, source: Player, player: Player, target: Player, targets: Player[], card: Card, cards: Card[], skill: string, forced: boolean, num: number, trigger: GameEventPromise, result: Result): any, + (event: GameEventPromise, trigger: GameEventPromise, player: Player): Promise; +} + +declare type Game = typeof import('../../noname/game/index.js').Game; +declare type Library = typeof import('../../noname/library/index.js').Library; declare type Status = typeof import('../../noname/status/index.js').status; -declare type UI = import('../../noname/ui/index.js').UI; -declare type Get = import('../../noname/get/index.js').Get; -declare type AI = import('../../noname/ai/index.js').AI; +declare type UI = typeof import('../../noname/ui/index.js').UI; +declare type Get = typeof import('../../noname/get/index.js').Get; +declare type AI = typeof import('../../noname/ai/index.js').AI; declare type Button = import('../../noname/library/index.js').Button; declare type Card = import('../../noname/library/index.js').Card; +declare type VCard = import('../../noname/library/index.js').VCard; declare type Dialog = import('../../noname/library/index.js').Dialog; declare type GameEvent = import('../../noname/library/index.js').GameEvent; declare type GameEventPromise = import('../../noname/library/index.js').GameEventPromise; @@ -39,4 +67,5 @@ declare type GameHistory = import('../../noname/game/index.js').GameHistory; declare type CodeMirror = typeof import('../../game/codemirror.js').default; declare type Sex = 'male' | 'female' | 'dobule' | 'none'; -declare type Character = [Sex, string, number | string, string[], string[]]; \ No newline at end of file +declare type Character = [Sex, string, number | string, string[], string[]]; +declare type Select = [number, number]; \ No newline at end of file diff --git a/node_modules/noname-typings/windowEx.d.ts b/node_modules/noname-typings/windowEx.d.ts index daaccc518..3d82e2a0f 100644 --- a/node_modules/noname-typings/windowEx.d.ts +++ b/node_modules/noname-typings/windowEx.d.ts @@ -69,16 +69,7 @@ declare interface Window { ai: AI; } - initReadWriteFunction?(game = ({ - download: () => any, - readFile: () => any, - readFileAsText: () => any, - writeFile: () => any, - removeFile: () => any, - getFileList: () => any, - ensureDirectory: () => any, - createDir: () => any, - })): void; + initReadWriteFunction?(game: Game): void; bannedKeyWords: string[]; } diff --git a/noname-server.exe b/noname-server.exe new file mode 100644 index 000000000..fe11b946d Binary files /dev/null and b/noname-server.exe differ diff --git a/noname/game/index.js b/noname/game/index.js index b824aff41..39e03eaf5 100644 --- a/noname/game/index.js +++ b/noname/game/index.js @@ -1364,19 +1364,21 @@ export class Game extends Uninstantable { else if (!path.startsWith('db:')) path = `audio/${path}`; if (!lib.config.repeat_audio && _status.skillaudio.includes(path)) return; } - _status.skillaudio.add(path); - game.addVideo('playAudio', null, path); - setTimeout(() => _status.skillaudio.remove(path), 1000); const audio = document.createElement('audio'); audio.autoplay = true; audio.volume = lib.config.volumn_audio / 8; - audio.addEventListener('ended', () => audio.remove()); - audio.onerror = event => { + //Some browsers do not support "autoplay", so "oncanplay" listening has been added + audio.oncanplay = () => Promise.resolve(audio.play()).catch(() => void 0); + audio.onplay = () => { + _status.skillaudio.add(path); + setTimeout(() => _status.skillaudio.remove(path), 1000); + game.addVideo("playAudio", null, path); + }; + audio.onended = (event) => audio.remove(); + audio.onerror = (event) => { audio.remove(); if (onError) onError(event); }; - //Some browsers do not support "autoplay", so "oncanplay" listening has been added - audio.oncanplay = () => Promise.resolve(audio.play()).catch(() => void 0); new Promise((resolve, reject) => { if (path.startsWith('db:')) game.getDB('image', path.slice(3)).then(octetStream => resolve(get.objectURL(octetStream)), reject); else if (lib.path.extname(path)) resolve(`${lib.assetURL}${path}`); @@ -4213,6 +4215,7 @@ export class Game extends Uninstantable { * @param { string } skill * @param { Player } player * @param { GameEventPromise } event + * @returns { GameEventPromise } */ static createTrigger(name, skill, player, event) { let info = get.info(skill); @@ -4227,6 +4230,7 @@ export class Game extends Uninstantable { next.includeOut = true; next._trigger = event; next.setContent('createTrigger'); + return next; } /** * @legacy Use {@link lib.element.GameEvent.constructor} instead. @@ -5362,10 +5366,11 @@ export class Game extends Uninstantable { * @param { GameEventPromise } [belongAsyncEvent] */ static async loop(belongAsyncEvent) { + if (!game.belongAsyncEventList) game.belongAsyncEventList = []; if (belongAsyncEvent) { - game.belongAsyncEvent = belongAsyncEvent; - } else if (game.belongAsyncEvent) { - return game.loop(game.belongAsyncEvent); + game.belongAsyncEventList.push(belongAsyncEvent); + } else if (game.belongAsyncEventList.length) { + belongAsyncEvent = game.belongAsyncEventList.at(-1); } while (true) { let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; @@ -5443,8 +5448,8 @@ export class Game extends Uninstantable { event.parent._result = event.result; } _status.event = event.parent; - if (game.belongAsyncEvent == event) { - delete game.belongAsyncEvent; + if (game.belongAsyncEventList.includes(event)) { + game.belongAsyncEventList.remove(event); } _resolve(); // 此时应该退出了 @@ -5453,8 +5458,8 @@ export class Game extends Uninstantable { } } else { - if (game.belongAsyncEvent == event) { - delete game.belongAsyncEvent; + if (game.belongAsyncEventList.includes(event)) { + game.belongAsyncEventList.remove(event); } return _resolve(); } @@ -6017,7 +6022,18 @@ export class Game extends Uninstantable { if (info.usable && get.skillCount(skills2[i]) >= info.usable) enable = false; if (info.chooseButton && _status.event.noButton) enable = false; if (info.round && (info.round - (game.roundNumber - player.storage[skills2[i] + '_roundcount']) > 0)) enable = false; - if (player.storage[`temp_ban_${skills2[i]}`] === true) enable = false; + for (const item in player.storage) { + if (item.startsWith('temp_ban_')) { + if(player.storage[item] !== true) continue; + const skillName = item.slice(9); + if (lib.skill[skillName]) { + const skills=game.expandSkills([skillName]); + if(skills.includes(skills2[i])) { + enable = false; break; + } + } + } + } } if (enable) { if (event.isMine() || !event._aiexclude.includes(skills2[i])) { @@ -7135,14 +7151,14 @@ export class Game extends Uninstantable { event.avatars[i].classList.add('selecting'); } } - let rand2 = []; + let rand = []; for (let i = 0; i < event.config.width; i++) { for (let j = 0; j < event.config.width - i; j++) { - rand2.push(i); + rand.push(i); } } for (let i = 0; i < event.config.num; i++) { - let rand2 = rand2.randomGet(); + let rand2 = rand.randomGet(); for (let j = 0; j < rand2.length; j++) { if (rand2[j] == rand2) { rand2.splice(j--, 1); diff --git a/noname/get/index.js b/noname/get/index.js index 955765fc9..cf0c34341 100644 --- a/noname/get/index.js +++ b/noname/get/index.js @@ -814,6 +814,7 @@ export class Get extends Uninstantable { "[object Object]": true, "[object Array]": true, "[object Arguments]": true, + "[object Date]": true }; if (typeof obj !== "object" || obj === null || !canTranverse[getType(obj)]) @@ -827,16 +828,22 @@ export class Get extends Uninstantable { const target = constructor ? ( - // 这三类数据处理单独处理 + // 这四类数据处理单独处理 // (实际上需要处理的只有Map和Set) // 除此之外的就只能祝愿有拷贝构造函数了 - (Array.isArray(obj) || obj instanceof Map || obj instanceof Set) + (Array.isArray(obj) || obj instanceof Map || obj instanceof Set || constructor === Object) // @ts-ignore ? new constructor() - // @ts-ignore - : new constructor(obj) + : ( + (constructor.name in window && /\[native code\]/.test(constructor.toString())) + // @ts-ignore + ? new constructor(obj) + : obj + ) ) : Object.create(null); + if (target === obj) return target; + map.set(obj, target); if (obj instanceof Map) { @@ -1360,11 +1367,13 @@ export class Get extends Uninstantable { } static infoFuncOL(info) { var func; + const str = info.slice(13).trim(); try { - eval('func=(' + info.slice(13) + ');'); - } - catch (e) { - return function () { }; + if (str.startsWith("function") || str.startsWith("(")) eval(`func=(${str});`); + else eval(`func=(function ${str});`); + } catch (e) { + console.error(`${e} in \n${str}`); + return function () {}; } if (Array.isArray(func)) { func = get.filter.apply(this, get.parsedResult(func)); @@ -1954,8 +1963,8 @@ export class Get extends Uninstantable { } } /** - * @param { number | [number, number] | (()=>[number, number]) } [select] - * @returns { [number, number] } + * @param { number | Select | (()=>Select) } [select] + * @returns { Select } */ static select(select) { if (typeof select == 'function') return get.select(select()); @@ -3007,7 +3016,16 @@ export class Get extends Uninstantable { var js = node.getCards('j'); for (var i = 0; i < js.length; i++) { if (js[i].viewAs && js[i].viewAs != js[i].name) { - uiintro.add('
    ' + js[i].outerHTML + '
    ' + lib.translate[js[i].viewAs] + ':' + lib.translate[js[i].viewAs + '_info'] + '
    '); + let html = js[i].outerHTML; + let cardInfo = lib.card[js[i].viewAs], showCardIntro=true; + if (cardInfo.blankCard) { + var cardOwner = get.owner(js[i]); + if (cardOwner && !cardOwner.isUnderControl(true)) showCardIntro = false; + } + if (!showCardIntro) { + html=ui.create.button(js[i],'blank').outerHTML; + } + uiintro.add('
    ' + html + '
    ' + lib.translate[js[i].viewAs] + ':' + lib.translate[js[i].viewAs + '_info'] + '
    '); } else { uiintro.add('
    ' + js[i].outerHTML + '
    ' + lib.translate[js[i].name + '_info'] + '
    '); @@ -3477,7 +3495,7 @@ export class Get extends Uninstantable { const defaultYingbianEffect = get.defaultYingbianEffect(node.link || node); if (lib.yingbian.prompt.has(defaultYingbianEffect)) yingbianEffects.push(defaultYingbianEffect); } - if (yingbianEffects.length) uiintro.add(`
    应变:${yingbianEffects.map(value => lib.yingbian.prompt.get(value)).join(';')}
    `); + if (yingbianEffects.length && showCardIntro) uiintro.add(`
    应变:${yingbianEffects.map(value => lib.yingbian.prompt.get(value)).join(';')}
    `); } if (lib.translate[name + '_append']) { uiintro.add('
    ' + lib.translate[name + '_append'] + '
    '); diff --git a/noname/get/is.js b/noname/get/is.js index 7d8796e0a..a5dee8a87 100644 --- a/noname/get/is.js +++ b/noname/get/is.js @@ -332,7 +332,7 @@ export class Is extends Uninstantable { } return true; } - static altered() { return false; } + static altered(skillName) { return false; } /* skill=>{ return false; diff --git a/noname/init/cordova.js b/noname/init/cordova.js index 38a939fa3..b642fad9d 100644 --- a/noname/init/cordova.js +++ b/noname/init/cordova.js @@ -17,7 +17,7 @@ export async function cordovaReady() { } }); document.addEventListener("resume", () => { - if (ui.backgroundMusic) ui.backgroundMusic.play(); + if (ui.backgroundMusic && !isNaN(ui.backgroundMusic.duration)) ui.backgroundMusic.play(); }); document.addEventListener("backbutton", function () { if (ui.arena && ui.arena.classList.contains('menupaused')) { diff --git a/noname/init/import.js b/noname/init/import.js index c08354319..e09689ea4 100644 --- a/noname/init/import.js +++ b/noname/init/import.js @@ -1,4 +1,5 @@ import { Game as game } from '../game/index.js'; +import { lib } from '../library/index.js'; /** * @param {string} name - 卡牌包名 @@ -33,7 +34,20 @@ export const importMode = generateImportFunction('mode', (name) => `../../mode/$ */ function generateImportFunction(type, pathParser) { return async (name) => { - const modeContent = await import(pathParser(name)); + const path = pathParser(name); + // 通过浏览器自带的script标签导入可直接获取报错信息,且不会影响JS运行 + // 此时代码内容也将缓存在浏览器中,故再次import后将不会重新执行代码内容(测试下来如此) + const [status, script] = await new Promise((resolve) => { + const script = document.createElement('script'); + script.type = 'module'; + script.src = `${lib.assetURL}noname/init/${path}`; + script.onerror = () => resolve(['error', script]); + script.onload = () => resolve(['ok', script]); + document.head.appendChild(script); + }); + script.remove(); + if (status === 'error') return; + const modeContent = await import(path); if (!modeContent.type) return; if (modeContent.type !== type) throw new Error(`Loaded Content doesn't conform to "${type}" but "${modeContent.type}".`); await game.import(type, modeContent.default); diff --git a/noname/init/index.js b/noname/init/index.js index 1cc23525d..02835a5f8 100644 --- a/noname/init/index.js +++ b/noname/init/index.js @@ -58,7 +58,7 @@ export async function boot() { _status.event = lib.element.GameEvent.initialGameEvent(); setWindowListener(); - await setOnError(); + const promiseErrorHandler = await setOnError(); // 无名杀更新日志 if (window.noname_update) { @@ -468,6 +468,7 @@ export async function boot() { if (extensionlist.length && (config.get('mode') != 'connect' || show_splash)) { _status.extensionLoading = []; + _status.extensionLoaded = []; const bannedExtensions = Reflect.get(window, 'bannedExtensions'); @@ -477,8 +478,25 @@ export async function boot() { extensionsLoading.push(importExtension(name)); } - await Promise.allSettled(extensionsLoading); - await Promise.allSettled(_status.extensionLoading); + const extErrorList = []; + for (const promise of extensionsLoading) { + await promise.catch(async (error) => { + extErrorList.add(error); + if (!promiseErrorHandler || !promiseErrorHandler.onHandle) return; + // @ts-ignore + await promiseErrorHandler.onHandle({ promise }); + }); + } + for (const promise of _status.extensionLoading) { + await promise.catch(async (error) => { + if (extErrorList.includes(error)) return; + if (!promiseErrorHandler || !promiseErrorHandler.onHandle) return; + // @ts-ignore + await promiseErrorHandler.onHandle({ promise }); + }); + } + // await Promise.allSettled(_status.extensionLoading); + _status.extensionLoaded.filter(Boolean).forEach((name) => { lib.announce.publish("Noname.Init.Extension.onLoad", name); lib.announce.publish(`Noname.Init.Extension.${name}.onLoad`, void 0); @@ -843,7 +861,8 @@ async function setOnError() { } } //解析parsex里的content fun内容(通常是技能content) - else if (err && err.stack && err.stack.split('\n')[1].trim().startsWith('at Object.eval [as content]')) { + // @ts-ignore + else if (err && err.stack && ['at Object.eval [as content]', 'at Proxy.content'].some(str => err.stack.split('\n')[1].trim().startsWith(str))) { const codes = _status.event.content; if (typeof codes == 'function') { const lines = codes.toString().split("\n"); @@ -867,6 +886,8 @@ async function setOnError() { game.loop(); } }; + + return promiseErrorHandler; } function setWindowListener() { diff --git a/noname/library/element/content.js b/noname/library/element/content.js index ecd7a9dc7..3e97d22a0 100644 --- a/noname/library/element/content.js +++ b/noname/library/element/content.js @@ -393,6 +393,14 @@ export const Content = { event.swapped = true; } "step 5"; + if (get.itemtype(result) == 'cards') { + for (let card of result){ + if (card.willBeDestroyed('discardPile', player, event)) { + card.selfDestroy(event); + } + } + } + "step 6"; //if(player.isMin() || player.countCards('e',{subtype:get.subtype(card)})){ if (player.isMin() || !player.canEquip(card)) { event.finish(); @@ -411,7 +419,7 @@ export const Content = { game.addVideo('equip', player, get.cardInfo(card)); if (event.log != false) game.log(player, '装备了', card); if (event.updatePile) game.updateRoundNumber(); - "step 6"; + "step 7"; var info = get.info(card, false); if (info.onEquip && (!info.filterEquip || info.filterEquip(card, player))) { if (Array.isArray(info.onEquip)) { @@ -476,6 +484,9 @@ export const Content = { else black.push([target, card]); } event.red = red; event.black = black; + event.trigger('debateShowOpinion'); + 'step 2' + var red = event.red, black = event.black; if (red.length) { game.log(red.map(function (i) { return i[0]; @@ -528,7 +539,7 @@ export const Content = { dialog.open(); }, get.translation(player), event.videoId, red, black); game.delay(4); - 'step 2'; + 'step 3'; game.broadcastAll('closeDialog', event.videoId); var opinion = null; if (event.red.length > event.black.length) opinion = 'red'; @@ -542,7 +553,7 @@ export const Content = { black: event.black, targets: event.targets }; - 'step 3'; + 'step 4'; if (event.callback) { var next = game.createEvent('debateCallback', false); next.player = player; @@ -1999,47 +2010,57 @@ export const Content = { event.callback(); } }, - arrangeTrigger: function () { - 'step 0'; - event.doing = event.doingList[0]; - if (event.doing && event.doing.todoList.length) return; - if (event.doingList.length) { - event.doingList.shift(); - return event.redo(); + arrangeTrigger: async function (event,trigger,player) { + while(event.doingList.length>0){ + event.doing = event.doingList.shift(); + while(true){ + if (trigger.filterStop && trigger.filterStop()) return; + const usableSkills = event.doing.todoList.filter(info => { + if (!lib.filter.filterTrigger(trigger, info.player, event.triggername, info.skill)) return false; + return lib.skill.global.includes(info.skill) || info.player.hasSkill(info.skill, true); + }); + if (usableSkills.length == 0){ + break; + } + else { + event.doing.todoList = event.doing.todoList.filter(i => i.priority <= usableSkills[0].priority); + //firstDo时机和lastDo时机不进行技能优先级选择 + if (get.itemtype(event.doing.player) !== 'player'){ + event.current = usableSkills[0]; + } + else { + event.choice = usableSkills.filter(n => n.priority == usableSkills[0].priority); + //现在只要找到一个同优先度技能为silent 便优先执行该技能 + const silentSkill = event.choice.find(item => { + const skillInfo = lib.skill[item.skill]; + return (skillInfo && skillInfo.silent); + }) + if (silentSkill){ + event.current = silentSkill; + } + else { + const currentChoice = event.choice[0]; + if (event.choice.length == 1) { + event.current = currentChoice; + } + else{ + const currentPlayer = currentChoice.player , skillsToChoose = event.choice.map(i => i.skill); + const next = currentPlayer.chooseControl(skillsToChoose); + next.set('prompt', '选择下一个触发的技能'); + next.set('forceDie', true); + next.set('arrangeSkill', true); + next.set('includeOut', true); + const {result} = await next; + event.current = event.doing.todoList.find(info => info.skill == result.control); + } + } + } + event.doing.doneList.push(event.current); + event.doing.todoList.remove(event.current); + await game.createTrigger(event.triggername, event.current.skill, event.current.player, trigger); + } + } } - event.finish(); - 'step 1'; - if (trigger.filterStop && trigger.filterStop()) return event.finish(); - event.current = event.doing.todoList.find(info => lib.filter.filterTrigger(trigger, info.player, event.triggername, info.skill)); - if (!event.current) { - event.doing.todoList = []; - return event.goto(0); - } - event.doing.todoList = event.doing.todoList.filter(i => i.priority <= event.current.priority); - - const directUse = info => lib.skill[info.skill].silent || !lib.translate[info.skill];//是否不触发同顺序选择 - if (directUse(event.current)) return event.goto(4); - event.choice = event.doing.todoList.filter(info => { - if (!lib.filter.filterTrigger(trigger, info.player, event.triggername, info.skill)) return false; - if (directUse(info)) return false; - if (event.current.player !== info.player) return false; - return lib.skill.global.includes(info.skill) || event.current.player.hasSkill(info.skill, true); - }); - if (event.choice.length < 2) return event.goto(4); - 'step 2'; - const next = event.choice[0].player.chooseControl(event.choice.map(i => i.skill)); - next.set('prompt', '选择下一个触发的技能'); - next.set('forceDie', true); - next.set('arrangeSkill', true); - next.set('includeOut', true); - 'step 3'; - if (result.control) event.current = event.doing.todoList.find(info => info.skill == result.control && info.player == event.choice[0].player); - 'step 4'; - if (!event.current || !event.doing.todoList.includes(event.current)) return; - event.doing.doneList.push(event.current); - event.doing.todoList.remove(event.current); - game.createTrigger(event.triggername, event.current.skill, event.current.player, trigger); - event.goto(0); }, createTrigger: function () { "step 0"; @@ -2143,11 +2164,11 @@ export const Content = { next._trigger = trigger; next.triggername = event.triggername; - if ("contents" in info && Array.isArray(info.contents)) { - next.setContents(info.contents); - } else { + // if ("contents" in info && Array.isArray(info.contents)) { + // next.setContents(info.contents); + // } else { next.setContent(info.content); - } + // } next.skillHidden = event.skillHidden; if (info.forceDie) next.forceDie = true; @@ -8163,7 +8184,12 @@ export const Content = { cards[0].classList.add('fakejudge'); cards[0].node.background.innerHTML = lib.translate[cards[0].viewAs + '_bg'] || get.translation(cards[0].viewAs)[0]; } - game.log(player, '被贴上了' + get.translation(cards[0].viewAs) + '(', cards, ')'); + if(lib.card[viewAs].blankCard){ + game.log(player, '被扣置了' + get.translation(cards[0].viewAs) + ''); + } + else { + game.log(player, '被贴上了' + get.translation(cards[0].viewAs) + '(', cards, ')'); + } } else { cards[0].classList.remove('fakejudge'); diff --git a/noname/library/element/gameEvent.js b/noname/library/element/gameEvent.js index d1ff882ac..a819ecf51 100644 --- a/noname/library/element/gameEvent.js +++ b/noname/library/element/gameEvent.js @@ -45,6 +45,10 @@ export class GameEvent { }; this._aiexclude = []; this._notrigger = []; + /** + * @type { Result } + */ + // @ts-ignore this._result = {}; this._set = []; /** @@ -738,7 +742,7 @@ export class GameEvent { untrigger(all = true, player) { const evt = this._triggering; if (all) { - this._triggered = 5; + if(all !== 'currentOnly') this._triggered = 5; if (evt && evt.doingList) { evt.doingList.forEach(doing => doing.todoList = []); } @@ -749,11 +753,6 @@ export class GameEvent { // const doing=evt.doingList.find(doing=>doing.player==player); // if(doing) doing.todoList=[]; } - else if (all==='currentOnly'){ - if (evt && evt.doingList) { - evt.doingList.forEach(doing => doing.todoList = []); - } - } return this; } /** @@ -862,6 +861,11 @@ export class GameEvent { */ // @ts-ignore this.excludeButton; + /** + * @type { Result } + */ + // @ts-ignore + this.result; throw new Error('Do not call this method'); } } diff --git a/noname/library/element/gameEventPromise.js b/noname/library/element/gameEventPromise.js index 568b09a65..3b650cf5c 100644 --- a/noname/library/element/gameEventPromise.js +++ b/noname/library/element/gameEventPromise.js @@ -16,7 +16,7 @@ import { AsyncFunction } from '../../util/index.js'; * 且Promise的原有属性无法被修改,一切对这个类实例的属性修改,删除, * 再配置等操作都会转发到事件对应的属性中。 * - * @todo 需要完成异步事件的debugger方法 + * @template { GameEvent } T * * @example * 使用await xx()等待异步事件执行: diff --git a/noname/library/element/vcard.js b/noname/library/element/vcard.js index a0bc68e30..30b4d58b6 100644 --- a/noname/library/element/vcard.js +++ b/noname/library/element/vcard.js @@ -1,132 +1,125 @@ -import { AI as ai } from '../../ai/index.js'; -import { Get as get } from '../../get/index.js'; -import { Game as game } from '../../game/index.js'; -import { Library as lib } from "../index.js"; -import { status as _status } from '../../status/index.js'; -import { UI as ui } from '../../ui/index.js'; - -export class VCard { - /** - * @param { any } [suitOrCard] - * @param { number | Card[] } [numberOrCards] - * @param { string } [name] - * @param { string } [nature] - */ - constructor(suitOrCard, numberOrCards, name, nature) { - if (suitOrCard instanceof VCard) { - const other = suitOrCard; - [suitOrCard, numberOrCards, name, nature] = other._args; - } - - if (Array.isArray(suitOrCard)) { - /** - * @type {string} - */ - this.suit = suitOrCard[0]; - /** - * @type {number} - */ - this.number = suitOrCard[1]; - /** - * @type {string} - */ - this.name = suitOrCard[2]; - /** - * @type {string} - */ - this.nature = suitOrCard[3]; - } - // @ts-ignore - else if (get.itemtype(suitOrCard) == 'card') { - this.name = get.name(suitOrCard); - this.suit = get.suit(suitOrCard); - this.color = get.color(suitOrCard); - this.number = get.number(suitOrCard); - this.nature = get.nature(suitOrCard); - /** - * @type { boolean } - */ - this.isCard = true; - this.cardid = suitOrCard.cardid; - this.wunature = suitOrCard.wunature; - /** - * @type {Record} - */ - this.storage = get.copy(suitOrCard.storage); - if (Array.isArray(numberOrCards)) this.cards = numberOrCards.slice(); - else this.cards = [suitOrCard]; - const info = get.info(this, false); - if (info) { - const autoViewAs = info.autoViewAs; - if (typeof autoViewAs == 'string') this.name = autoViewAs; - } - } - else if (suitOrCard && typeof suitOrCard != 'string') { - Object.keys(suitOrCard).forEach(key => { - /** - * @type { PropertyDescriptor } - */ - // @ts-ignore - const propertyDescriptor = Object.getOwnPropertyDescriptor(suitOrCard, key), value = propertyDescriptor.value; - if (Array.isArray(value)) this[key] = value.slice(); - else Object.defineProperty(this, key, propertyDescriptor); - }); - if (Array.isArray(numberOrCards)) { - const noCards = !this.cards; - /** - * @type { Card[] } - */ - this.cards = numberOrCards.slice(); - if (noCards) { - if (!lib.suits.includes(this.suit)) this.suit = get.suit(this); - if (!Object.keys(lib.color).includes(this.color)) this.color = get.color(this); - if (typeof this.number != 'number') this.number = get.number(this); - if (!this.nature) this.nature = get.nature(this); - } - } - const info = get.info(this, false); - if (info) { - const autoViewAs = info.autoViewAs; - if (typeof autoViewAs == 'string') this.name = autoViewAs; - } - } - if (typeof suitOrCard == 'string') this.suit = suitOrCard; - if (typeof numberOrCards == 'number') this.number = numberOrCards; - if (typeof name == 'string') this.name = name; - if (typeof nature == 'string') this.nature = nature; - if (!this.storage) this.storage = {}; - if (!this.cards) this.cards = []; - - this._args = [suitOrCard, numberOrCards, name, nature]; - } - sameSuitAs(card) { - return get.suit(this) == get.suit(card); - } - differentSuitFrom(card) { - return get.suit(this) != get.suit(card); - } - sameNumberAs(card) { - return get.number(this) == get.number(card); - } - differentNumberFrom(card) { - return get.number(this) != get.number(card); - } - sameNameAs(card) { - return get.name(this) == get.name(card); - } - differentNameFrom(card) { - return get.name(this) != get.name(card); - } - /** - * @param { Player } player - */ - hasNature(nature, player) { - const natures = get.natureList(this, player); - if (!nature) return natures.length > 0; - if (nature == 'linked') return natures.some(n => lib.linked.includes(n)); - return get.is.sameNature(natures, nature); - } - hasGaintag(tag) { - return this.gaintag && this.gaintag.includes(tag); - } -} +import { AI as ai } from '../../ai/index.js'; +import { Get as get } from '../../get/index.js'; +import { Game as game } from '../../game/index.js'; +import { Library as lib } from "../index.js"; +import { status as _status } from '../../status/index.js'; +import { UI as ui } from '../../ui/index.js'; + +export class VCard { + /** + * @param { any } [suitOrCard] + * @param { number | Card[] } [numberOrCards] + * @param { string } [name] + * @param { string } [nature] + */ + constructor(suitOrCard, numberOrCards, name, nature) { + if (Array.isArray(suitOrCard)) { + /** + * @type {string} + */ + this.suit = suitOrCard[0]; + /** + * @type {number} + */ + this.number = suitOrCard[1]; + /** + * @type {string} + */ + this.name = suitOrCard[2]; + /** + * @type {string} + */ + this.nature = suitOrCard[3]; + } + // @ts-ignore + else if (get.itemtype(suitOrCard) == 'card') { + this.name = get.name(suitOrCard); + this.suit = get.suit(suitOrCard); + this.color = get.color(suitOrCard); + this.number = get.number(suitOrCard); + this.nature = get.nature(suitOrCard); + /** + * @type { boolean } + */ + this.isCard = true; + this.cardid = suitOrCard.cardid; + this.wunature = suitOrCard.wunature; + /** + * @type {Record} + */ + this.storage = get.copy(suitOrCard.storage); + if (Array.isArray(numberOrCards)) this.cards = numberOrCards.slice(); + else this.cards = [suitOrCard]; + const info = get.info(this, false); + if (info) { + const autoViewAs = info.autoViewAs; + if (typeof autoViewAs == 'string') this.name = autoViewAs; + } + } + else if (suitOrCard && typeof suitOrCard != 'string') { + Object.keys(suitOrCard).forEach(key => { + /** + * @type { PropertyDescriptor } + */ + // @ts-ignore + const propertyDescriptor = Object.getOwnPropertyDescriptor(suitOrCard, key), value = propertyDescriptor.value; + if (Array.isArray(value)) this[key] = value.slice(); + else Object.defineProperty(this, key, propertyDescriptor); + }); + if (Array.isArray(numberOrCards)) { + const noCards = !this.cards; + /** + * @type { Card[] } + */ + this.cards = numberOrCards.slice(); + if (noCards) { + if (!lib.suits.includes(this.suit)) this.suit = get.suit(this); + if (!Object.keys(lib.color).includes(this.color)) this.color = get.color(this); + if (typeof this.number != 'number') this.number = get.number(this); + if (!this.nature) this.nature = get.nature(this); + } + } + const info = get.info(this, false); + if (info) { + const autoViewAs = info.autoViewAs; + if (typeof autoViewAs == 'string') this.name = autoViewAs; + } + } + if (typeof suitOrCard == 'string') this.suit = suitOrCard; + if (typeof numberOrCards == 'number') this.number = numberOrCards; + if (typeof name == 'string') this.name = name; + if (typeof nature == 'string') this.nature = nature; + if (!this.storage) this.storage = {}; + if (!this.cards) this.cards = []; + } + sameSuitAs(card) { + return get.suit(this) == get.suit(card); + } + differentSuitFrom(card) { + return get.suit(this) != get.suit(card); + } + sameNumberAs(card) { + return get.number(this) == get.number(card); + } + differentNumberFrom(card) { + return get.number(this) != get.number(card); + } + sameNameAs(card) { + return get.name(this) == get.name(card); + } + differentNameFrom(card) { + return get.name(this) != get.name(card); + } + /** + * @param { Player } player + */ + hasNature(nature, player) { + const natures = get.natureList(this, player); + if (!nature) return natures.length > 0; + if (nature == 'linked') return natures.some(n => lib.linked.includes(n)); + return get.is.sameNature(natures, nature); + } + hasGaintag(tag) { + return this.gaintag && this.gaintag.includes(tag); + } +} diff --git a/noname/library/index.js b/noname/library/index.js index 6d04c9d4c..2c63d5759 100644 --- a/noname/library/index.js +++ b/noname/library/index.js @@ -1,13096 +1,13121 @@ -/** - * @typedef { InstanceType } Player - * @typedef { InstanceType } Card - * @typedef { InstanceType } VCard - * @typedef { InstanceType } Button - * @typedef { InstanceType } Dialog - * @typedef { InstanceType } GameEvent - * @typedef { InstanceType & InstanceType & typeof Promise } GameEventPromise - * @typedef { InstanceType } NodeWS - * @typedef { InstanceType } Control -*/ -import { nonameInitialized, assetURL, userAgent, Uninstantable, GeneratorFunction, AsyncFunction, characterDefaultPicturePath } from "../util/index.js"; -import { AI as ai } from '../ai/index.js'; -import { Get as get } from '../get/index.js'; -import { Game as game } from '../game/index.js'; -import { status as _status } from '../status/index.js'; -import { UI as ui } from '../ui/index.js'; -import { GNC as gnc } from '../gnc/index.js'; - -import { LibInit } from "./init/index.js"; -import { Announce } from "./announce/index.js"; -import { Channel } from "./channel/index.js"; -import { Experimental } from "./experimental/index.js"; -import * as Element from "./element/index.js"; - - -export class Library extends Uninstantable { - static configprefix = 'noname_0.9_'; - static versionOL = 27; - static updateURLS = { - coding: 'https://gitcode.net/sinat_33405273/noname/-/raw/', - github: 'https://raw.githubusercontent.com/libccy/noname', - }; - static updateURL = 'https://raw.githubusercontent.com/libccy/noname'; - static mirrorURL = 'https://gitcode.net/sinat_33405273/noname/-/raw/'; - static hallURL = '47.99.105.222'; - static assetURL = assetURL; - static userAgent = userAgent; - static characterDefaultPicturePath = characterDefaultPicturePath; - static compatibleEdition = Boolean(typeof nonameInitialized == 'string' && nonameInitialized.match(/\/(?:com\.widget|yuri\.nakamura)\.noname\//)); - static changeLog = []; - static updates = []; - static canvasUpdates = []; - /** - * @type { Video[] } - */ - static video = []; - static skilllist = []; - static connectBanned = []; - static characterIntro = {}; - static characterTitle = {}; - static characterPack = {}; - static characterFilter = {}; - static characterSort = {}; - static characterReplace = {}; - static characterGuozhanFilter = ["mode_guozhan"]; - static dynamicTranslate = {}; - static cardPack = {}; - /** - * @type { SMap } - */ - static skin = {}; - static onresize = []; - static onphase = []; - static onwash = []; - static onover = []; - static ondb = []; - static ondb2 = []; - static chatHistory = []; - static emotionList = { - xiaowu_emotion: 14, - xiaokuo_emotion: 8, - shibing_emotion: 15, - guojia_emotion: 20, - zhenji_emotion: 20, - xiaosha_emotion: 20, - xiaotao_emotion: 20, - xiaojiu_emotion: 20, - }; - static animate = { - skill: {}, - card: {}, - }; - static onload = []; - static onload2 = []; - static onprepare = []; - static arenaReady = []; - static onfree = []; - static inpile = []; - static inpile_nature = []; - static extensions = []; - static extensionPack = {}; - static cardType = {}; - static hook = { globalskill: {} }; - /** - * @returns { never } - */ - static typeAnnotation() { - /** - * @type { Videos[] } - */ - // @ts-ignore - this.videos; - /** - * @type { { - * fs: typeof import("fs"), - * path: typeof import("path"), - * debug: () => void, - * clients: Element.Client[], - * banned:[], - * observing:[], - * torespond:{}, - * torespondtimeout:{}, - * } } - */ - // @ts-ignore - this.node; - /** - * @type { { [key: string]: string } } - */ - // @ts-ignore - this.playerOL; - throw new Error('Do not call this method'); - } - - //函数钩子 - static hooks = { - // 本体势力的颜色 - addGroup: [(id, _short, _name, config) => { - if ("color" in config && config.color != null) { - let color1, color2, color3, color4; - if (typeof config.color == "string" && /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(config.color)) { - let c1 = parseInt(`0x${config.color.slice(1, 3)}`); - let c2 = parseInt(`0x${config.color.slice(3, 5)}`); - let c3 = parseInt(`0x${config.color.slice(5, 7)}`); - color1 = color2 = color3 = color4 = [c1, c2, c3, 1]; - } - else if (Array.isArray(config.color) && config.color.length == 4) { - if (config.color.every(item => Array.isArray(item))) { - color1 = config.color[0]; - color2 = config.color[1]; - color3 = config.color[2]; - color4 = config.color[3]; - } - else color1 = color2 = color3 = color4 = config.color; - } - if (color1 && color2 && color3 && color4) { - const cs = lib.linq.cselector; - const g1 = cs.group( - cs.of( - cs.class("player ", "identity"), - cs.isAttr("data-color", `"${id}"`) - ), - cs.of( - "div", - cs.isAttr("data-nature", `"${id}"`) - ), - cs.of( - "span", - cs.isAttr("data-nature", `"${id}"`) - ) - ); - const g2 = cs.group( - cs.of( - "div", - cs.isAttr("data-nature", `"${id}m"`) - ), - cs.of( - "span", - cs.isAttr("data-nature", `"${id}m"`) - ) - ); - const g3 = cs.group( - cs.of( - "div", - cs.isAttr("data-nature", `"${id}mm"`) - ), - cs.of( - "span", - cs.isAttr("data-nature", `"${id}mm"`) - ) - ); - let result = {}; - result[g1] = { - textShadow: cs.group( - "black 0 0 1px", - `rgba(${color1.join()}) 0 0 2px`, - `rgba(${color2.join()}) 0 0 5px`, - `rgba(${color3.join()}) 0 0 10px`, - `rgba(${color4.join()}) 0 0 10px` - ) - }; - result[g2] = { - textShadow: cs.group( - "black 0 0 1px", - `rgba(${color1.join()}) 0 0 2px`, - `rgba(${color2.join()}) 0 0 5px`, - `rgba(${color3.join()}) 0 0 5px`, - `rgba(${color4.join()}) 0 0 5px`, - "black 0 0 1px" - ) - }; - result[g3] = { - textShadow: cs.group( - "black 0 0 1px", - `rgba(${color1.join()}) 0 0 2px`, - `rgba(${color2.join()}) 0 0 2px`, - `rgba(${color3.join()}) 0 0 2px`, - `rgba(${color4.join()}) 0 0 2px`, - "black 0 0 1px" - ) - }; - game.dynamicStyle.addObject(result); - lib.groupnature[id] = id; - } - } - if (typeof config.image == 'string') Object.defineProperty(lib.card, `group_${id}`, { - configurable: true, - enumerable: false, - writable: true, - value: { - fullskin: true, - image: config.image - } - }); - }], - //增加新属性杀 - addNature: [(nature, _translation, config) => { - if (typeof config != 'object') config = {}; - let linked = config.linked, order = config.order, background = config.background, lineColor = config.lineColor; - if (typeof linked != 'boolean') linked = true; - if (typeof order != 'number') order = 0; - if (typeof background != 'string') background = ''; - if (!Array.isArray(lineColor) || lineColor.length != 3) lineColor = []; - else if (background.startsWith('ext:')) { - background = background.replace(/^ext:/, 'extension/'); - } - if (linked) lib.linked.add(nature); - if (lineColor.length) lib.lineColor.set(nature, lineColor); - lib.nature.set(nature, order); - if (background.length > 0) lib.natureBg.set(nature, background); - if (config.audio) { - for (let key in config.audio) { - if (!lib.natureAudio[key]) { - lib.natureAudio[key] = config.audio[key]; - } else { - for (let key2 in config.audio[key]) { - lib.natureAudio[key][key2] = config.audio[key][key2]; - } - } - } - } - - let color1, color2; - if (typeof config.color == "string" && /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(config.color)) { - let c1 = parseInt(`0x${item[1].slice(1, 3)}`); - let c2 = parseInt(`0x${item[1].slice(3, 5)}`); - let c3 = parseInt(`0x${item[1].slice(5, 7)}`); - color1 = color2 = [c1, c2, c3, 1]; - } - else if (Array.isArray(config.color) && config.color.length >= 2 && config.color.length <= 4) { - if (config.color.every(item => Array.isArray(item))) { - color1 = config.color[0]; - color2 = config.color[1]; - } - else { - let color = config.color.slice(); - if (color.length == 3) color.push(1); - color1 = color2 = color; - } - } - if (color1 && color2) { - const cs = lib.linq.cselector; - const g1 = cs.group( - cs.of( - cs.class("card", "fullskin", `${nature}`), - '>', - cs.class("name") - ) - ); - let result = {}; - result[g1] = { - color: `rgba(${color1.join()})`, - border: cs.merge( - '1px', - 'solid', - `rgba(${color2.join()})` - ), - }; - game.dynamicStyle.addObject(result); - - const g2 = cs.group( - cs.of( - cs.class("tempname", `${nature}`), - ':not([data-nature])>', - cs.class("span") - ) - ); - let result2 = {}; - result2[g2] = { - color: `rgba(${color1.join()})`, - }; - game.dynamicStyle.addObject(result2); - } - }], - }; - - /** - * **无名杀频道推送机制** - * - * 鉴于`Javascript`的特性及自身对所需功能的思考,这是一个参考`Golang`的`channel`设计的、完全和`go channel`不一样的异步消息传递对象 - * - * 当且仅当接收方和发送方均存在时进行消息传递,完全保证信息传递的单一性(发送方/接收方一旦确定则无法更改)和准确性(发送方必然将消息发送给接收方) - * - * 若存在发送方/接收方时调用`send`/`receive`,将报错 - * - * 若需要异步/不报错发送信息,请等待`lib.actor` - * - * @example - * // 创建一个频道 - * const channel = new lib.channel(); - * - * // 从某个角落接收channel发出的消息,若无消息则等待 - * const message = await channel.receive(); - * - * // 从某个角落向channel发消息,若无消息接收则等待 - * await channel.send(item); - */ - static channel = Channel; - - /** - * **无名杀消息推送库** - * - * 通过`EventTarget`机制,实现消息推送和接收的解耦, - * 从而使消息接收方无需依赖发布方,发布方也无需考虑接收方 - * - * > `lib.announce`不是`actor`模型,若不存在订阅者,则消息发送将无意义 - * - * @example - * // 甲扩展(如《千幻聆音》)在角色皮肤切换后,调用: - * lib.announce.publish("skinChange", { - * player, - * playerName: "zhangfei", - * originSkin: "image/xxx.jpg", - * currentSkin: "image/yyy.jpg" - * }); - * - * // 乙扩展监听此`skinChange`事件,并修改自己扩展相关界面的图片: - * const method = lib.announce.subscribe("skinChange", (e) => { - * div.setBackgroundImage(e.currentSkin); - * }); - * - * // 若此时乙扩展不想继续订阅`skinChange`事件,可以通过`unsubscribe`解除订阅 - * lib.announce.unsubscribe("skinChange", method); - */ - static announce = new Announce(new EventTarget(), new WeakMap()); - - static objectURL = new Map(); - static hookmap = {}; - static imported = {}; - static layoutfixed = ['chess', 'tafang', 'stone']; - static pinyins = { - _metadata: { - shengmu: ['zh', 'ch', 'sh', 'b', 'p', 'm', 'f', 'd', 't', 'l', 'n', 'g', 'k', 'h', 'j', 'q', 'x', 'r', 'z', 'c', 's', 'y', 'w'], - special_shengmu: ['j', 'q', 'x', 'y'], - feijiemu: { - i: ['ing', 'iu', 'ie', 'in'], - u: ['ui', 'un'], - ü: ['üe', 'ün'], - }, - zhengtirendu: ['zhi', 'chi', 'shi', 'ri', 'zi', 'ci', 'si'], - yunjiao: { - '一麻': ['a', 'ia', 'ua'], - '二波': ['o', 'e', 'uo'], - '三皆': ['ie', 'üe'], - '四开': ['ai', 'uai'], - '五微': ['ei', 'ui'], - '六豪': ['ao', 'iao'], - '七尤': ['ou', 'iu'], - '八寒': ['an', 'ian', 'uan', 'üan'], - '九文': ['en', 'in', 'un', 'ün'], - '十唐': ['ang', 'iang', 'uang'], - '十一庚': ['eng', 'ing', 'ong', 'ung'], - '十二齐': ['i', 'er', 'ü'], - '十三支': ['-i'], - '十四姑': ['u'], - }, - } - }; - /** - * Yingbian - * - * 应变 - */ - static yingbian = { - condition: { - color: new Map([ - ['zhuzhan', 'wood'], - ['kongchao', 'soil'], - ['fujia', 'orange'], - ['canqu', 'fire'], - ['force', 'metal'] - ]), - complex: new Map([ - ['zhuzhan', function (event) { - const yingbianZhuzhan = game.createEvent('yingbianZhuzhan'); - yingbianZhuzhan.player = event.player; - yingbianZhuzhan.card = event.card; - yingbianZhuzhan._trigger = event; - yingbianZhuzhan.yingbianZhuzhanAI = event.yingbianZhuzhanAI; - yingbianZhuzhan.afterYingbianZhuzhan = event.afterYingbianZhuzhan; - yingbianZhuzhan.setContent(() => { - 'step 0'; - event._global_waiting = true; - event.send = (player, card, source, targets, id, id2, yingbianZhuzhanAI, skillState) => { - if (skillState) player.applySkills(skillState); - var type = get.type2(card), str = get.translation(source); - if (targets && targets.length) str += `对${get.translation(targets)}`; - str += `使用了${get.translation(card)},是否弃置一张${get.translation(type)}为其助战?`; - player.chooseCard({ - filterCard: (card, player) => get.type2(card) == type && lib.filter.cardDiscardable(card, player), - prompt: str, - position: 'h', - _global_waiting: true, - id: id, - id2: id2, - ai: typeof yingbianZhuzhanAI == 'function' ? yingbianZhuzhanAI(player, card, source, targets) : cardx => { - var info = get.info(card); - if (info && info.ai && info.ai.yingbian) { - var ai = info.ai.yingbian(card, source, targets, player); - if (!ai) return 0; - return ai - get.value(cardx); - } - else if (get.attitude(player, source) <= 0) return 0; - return 5 - get.value(cardx); - } - }); - if (!game.online) return; - _status.event._resultid = id; - game.resume(); - }; - 'step 1'; - var type = get.type2(card); - event.list = game.filterPlayer(current => current != player && current.countCards('h') && (_status.connectMode || current.hasCard(cardx => get.type2(cardx) == type, 'h'))).sortBySeat(_status.currentPhase || player); - event.id = get.id(); - 'step 2'; - if (!event.list.length) event.finish(); - else if (_status.connectMode && (event.list[0].isOnline() || event.list[0] == game.me)) event.goto(4); - else event.send(event.current = event.list.shift(), event.card, player, trigger.targets, event.id, trigger.parent.id, trigger.yingbianZhuzhanAI); - 'step 3'; - if (result.bool) { - event.zhuzhanresult = event.current; - event.zhuzhanresult2 = result; - if (event.current != game.me) game.delayx(); - event.goto(8); - } - else event.goto(2); - 'step 4'; - var id = event.id, sendback = (result, player) => { - if (result && result.id == id && !event.zhuzhanresult && result.bool) { - event.zhuzhanresult = player; - event.zhuzhanresult2 = result; - game.broadcast('cancel', id); - if (_status.event.id == id && _status.event.name == 'chooseCard' && _status.paused) return () => { - event.resultOL = _status.event.resultOL; - ui.click.cancel(); - if (ui.confirm) ui.confirm.close(); - }; - } - else if (_status.event.id == id && _status.event.name == 'chooseCard' && _status.paused) return () => event.resultOL = _status.event.resultOL; - }, withme = false, withol = false, list = event.list; - for (var i = 0; i < list.length; i++) { - var current = list[i]; - if (current.isOnline()) { - withol = true; - current.wait(sendback); - current.send(event.send, current, event.card, player, trigger.targets, event.id, trigger.parent.id, trigger.yingbianZhuzhanAI, get.skillState(current)); - list.splice(i--, 1); - } - else if (current == game.me) { - withme = true; - event.send(current, event.card, player, trigger.targets, event.id, trigger.parent.id, trigger.yingbianZhuzhanAI); - list.splice(i--, 1); - } - } - if (!withme) event.goto(6); - if (_status.connectMode && (withme || withol)) game.players.forEach(value => { - if (value != player) value.showTimer(); - }); - event.withol = withol; - 'step 5'; - if (!result || !result.bool || event.zhuzhanresult) return; - game.broadcast('cancel', event.id); - event.zhuzhanresult = game.me; - event.zhuzhanresult2 = result; - 'step 6'; - if (event.withol && !event.resultOL) game.pause(); - 'step 7'; - game.players.forEach(value => value.hideTimer()); - 'step 8'; - if (event.zhuzhanresult) { - var target = event.zhuzhanresult; - target.line(player, 'green'); - target.discard(event.zhuzhanresult2.cards).discarder = target; - if (typeof event.afterYingbianZhuzhan == 'function') event.afterYingbianZhuzhan(event, trigger); - var yingbianCondition = event.name.slice(8).toLowerCase(), yingbianConditionTag = `yingbian_${yingbianCondition}_tag`; - target.popup(yingbianConditionTag, lib.yingbian.condition.color.get(yingbianCondition)); - game.log(target, '响应了', player, '发起的', yingbianConditionTag); - target.addExpose(0.2); - event.result = { - bool: true - }; - } - else event.result = { - bool: false - }; - }); - yingbianZhuzhan._args = Array.from(arguments); - return yingbianZhuzhan; - }] - ]), - simple: new Map([ - ['kongchao', event => !event.player.countCards('h')], - ['fujia', event => event.player.isMaxHandcard()], - ['canqu', event => event.player.getHp() == 1] - ]) - }, - effect: new Map([ - ['add', () => { - trigger.yingbian_addTarget = true; - }], - ['remove', () => { - trigger.yingbian_removeTarget = true; - }], - ['damage', () => { - if (typeof trigger.baseDamage != 'number') trigger.baseDamage = 1; - trigger.baseDamage++; - game.log(card, '的伤害值基数+1'); - }], - ['draw', () => { - player.draw(); - }], - ['gain', () => { - const cardx = trigger.respondTo; - if (cardx && cardx[1] && cardx[1].cards && cardx[1].cards.filterInD('od').length) player.gain(cardx[1].cards.filterInD('od'), 'gain2'); - }], - ['hit', () => { - trigger.directHit.addArray(game.players).addArray(game.dead); - game.log(card, '不可被响应'); - }], - ['all', () => { - card.yingbian_all = true; - game.log(card, '执行所有选项'); - }] - ]), - prompt: new Map([ - ['add', '目标+1'], - ['remove', '目标-1'], - ['damage', '伤害+1'], - ['draw', '摸一张牌'], - ['gain', '获得响应的牌'], - ['hit', '此牌不可被响应'], - ['all', '无视条件执行所有选项'] - ]) - }; - /** - * Stratagem buff - * - * 谋攻强化 - */ - static stratagemBuff = { - cost: new Map([ - ['sha', 1], - ['shan', 1], - ['juedou', 2], - ['huogong', 2], - ['tao', 3] - ]), - effect: new Map([ - ['sha', (event, option) => { - if (event.step != 0 || option.state != 'end') return; - game.log(event.player, '触发了强化效果'); - game.log(event.card, '抵消所需要的', new lib.element.VCard({ - name: 'shan' - }), '数+1'); - const map = event.customArgs; - game.players.concat(game.dead).forEach(current => { - const id = current.playerid; - if (!map[id]) map[id] = {}; - if (typeof map[id].shanRequired == 'number') map[id].shanRequired++; - else map[id].shanRequired = 2; - }); - }], - ['shan', (event, option) => { - if (event.step != 0 || option.state != 'end') return; - game.log(event.player, '触发了强化效果'); - game.log('使用', event.card, '时视为两张', new lib.element.VCard({ - name: 'shan' - }), '的效果'); - event.player.when('useCard').filter(evt => evt == event).then(() => { - trigger.getParent(2).decrease('shanRequired', 1); - }); - }], - ['juedou', (event, option) => { - if (event.step != 0 || option.state != 'end') return; - game.log(event.player, '触发了强化效果'); - game.log('对', event.card, '的目标造成伤害时,伤害+1'); - event.player.when({ - source: 'damageBegin1' - }).filter(evt => evt.getParent(2) == event && event.targets.includes(evt.player)).then(() => { - trigger.increase('num'); - }); - }], - ['huogong', (event, option) => { - if (event.step != 0 || option.state != 'end') return; - game.log(event.player, '触发了强化效果'); - game.log(event.card, '造成的伤害+1'); - event.increase('baseDamage', 1); - }], - ['tao', (event, option) => { - if (event.step != 0 || option.state != 'end') return; - game.log(event.player, '触发了强化效果'); - game.log(event.card, '回复的体力+1'); - event.increase('baseDamage', 1); - }] - ]), - prompt: new Map([ - [ - 'sha', - /** - * @type {() => string} - */ - () => `抵消所需要的【${get.translation('shan')}】数+1。` - ], - [ - 'shan', - /** - * @type {() => string} - */ - () => `使用时视为两张【${get.translation('shan')}】的效果。` - ], - [ - 'juedou', - () => '对此牌的目标造成伤害时,伤害+1。' - ], - [ - 'huogong', - () => '造成的伤害+1。' - ], - [ - 'tao', - () => '回复的体力+1。' - ] - ]) - }; - /** - * The actual card name - * - * 实际的卡牌名称 - */ - static actualCardName = new Map([ - ['挟令', '挟天子以令诸侯'], - ['霹雳投石车', '霹雳车'] - ]); - static characterDialogGroup = { - '收藏': function (name, capt) { - return lib.config.favouriteCharacter.includes(name) ? capt : null; - }, - '最近': function (name, capt) { - var list = get.config('recentCharacter') || []; - return list.includes(name) ? capt : null; - } - }; - static listenEnd(node) { - if (!node._listeningEnd) { - node._listeningEnd = true; - node.listenTransition(function () { - delete node._listeningEnd; - if (node._onEndMoveDelete) { - node.moveDelete(node._onEndMoveDelete); - } - else if (node._onEndDelete) { - node.delete(); - } - node._transitionEnded = true; - }); - } - } - static configMenu = { - general: { - name: '通用', - config: { - mount_combine: { - name: '合并坐骑栏', - init: false, - intro: '
  • 将进攻坐骑栏和防御坐骑栏合并为同一个位置(重启后生效)。', - restart: true, - }, - low_performance: { - name: '流畅模式', - init: false, - intro: '减少部分游戏特效,提高游戏速度', - onclick: function (bool) { - game.saveConfig('low_performance', bool); - if (bool) { - ui.window.classList.add('low_performance'); - } - else { - ui.window.classList.remove('low_performance'); - } - } - }, - compatiblemode: { - name: '兼容模式', - init: false, - intro: '开启兼容模式可防止扩展使游戏卡死并提高对旧扩展的兼容性,但对游戏速度有一定影响,若无不稳定或不兼容的扩展建议关闭', - onclick: function (bool) { - game.saveConfig('compatiblemode', bool); - if (bool) { - ui.window.classList.add('compatiblemode'); - } - else { - ui.window.classList.remove('compatiblemode'); - } - } - }, - confirm_exit: { - name: '确认退出', - init: false, - unfrequent: true, - intro: '离开游戏前弹出确认对话框', - }, - keep_awake: { - name: '屏幕常亮', - init: false, - unfrequent: true, - intro: '防止屏幕自动关闭
    注:旧版本通过NoSleep.js实现的屏幕常亮可能会影响外置音频的音量', - onclick: function (bool) { - game.saveConfig('keep_awake', bool); - if (bool) { - if (window.plugins && window.plugins.insomnia) window.plugins.insomnia.keepAwake(); - else if (window.noSleep) { - document.addEventListener(lib.config.touchscreen ? 'touchend' : 'click', function enableNoSleepX() { - document.removeEventListener(lib.config.touchscreen ? 'touchend' : 'click', enableNoSleepX, false); - window.noSleep.enable(); - }, false); - } - } - else { - if (window.plugins && window.plugins.insomnia) window.plugins.insomnia.allowSleepAgain(); - else if (window.noSleep) window.noSleep.disable(); - } - } - }, - auto_confirm: { - name: '自动确认', - init: true, - unfrequent: true, - intro: '当候选目标只有1个时,点击目标后无需再点击确认', - }, - skip_shan: { - name: '无闪自动取消', - init: false, - unfrequent: true, - intro: '当自己需要使用或打出【闪】时,若自己没有【闪】,则跳过该步骤', - }, - unauto_choose: { - name: '拆顺手牌选择', - init: false, - unfrequent: true, - intro: '拆牌或者顺牌时,就算只能选择对方的手牌依然手动选择', - }, - wuxie_self: { - name: '不无懈自己', - init: true, - unfrequent: true, - intro: '自己使用的单目标普通锦囊即将生效时,不询问无懈', - }, - tao_enemy: { - name: '不对敌方出桃', - init: false, - intro: '双方阵营明确的模式中(如对决),敌方角色濒死时不询问出桃', - unfrequent: true, - }, - enable_drag: { - name: '启用拖拽', - init: true, - intro: '按住卡牌后可将卡牌拖至目标', - unfrequent: true, - }, - enable_dragline: { - name: '拖拽指示线', - init: true, - unfrequent: true, - intro: '拖拽时显示虚线,可能降低游戏速度', - }, - enable_touchdragline: { - name: '拖拽指示线', - init: false, - unfrequent: true, - intro: '拖拽时显示虚线,可能降低游戏速度', - }, - // enable_pressure:{ - // name:'启用压感', - // init:false, - // intro:'开启后可通过按压执行操作', - // unfrequent:true, - // }, - // pressure_taptic:{ - // name:'触觉反馈', - // init:false, - // intro:'开启后按压操作执行时将产生震动', - // unfrequent:true, - // }, - // pressure_click:{ - // name:'按压操作', - // init:'pause', - // intro:'在空白区域按压时的操作', - // unfrequent:true, - // item:{ - // pause:'暂停', - // config:'选项', - // auto:'托管', - // } - // }, - touchscreen: { - name: '触屏模式', - init: false, - restart: true, - unfrequent: true, - intro: '开启后可使触屏设备反应更快,但无法使用鼠标操作', - onclick: function (bool) { - if (get.is.nomenu('touchscreen', bool)) return false; - game.saveConfig('touchscreen', bool); - } - }, - swipe: { - name: '滑动手势', - init: true, - unfrequent: true, - intro: '在非滚动区域向四个方向滑动可执行对应操作', - }, - swipe_down: { - name: '下划操作', - init: 'menu', - unfrequent: true, - intro: '向下滑动时执行的操作', - item: { - system: '显示按钮', - menu: '打开菜单', - pause: '切换暂停', - auto: '切换托管', - chat: '显示聊天', - off: '关闭', - }, - onclick: function (item) { - if (get.is.nomenu('swipe_down', item)) return false; - game.saveConfig('swipe_down', item); - } - }, - swipe_up: { - name: '上划操作', - intro: '向上滑动时执行的操作', - init: 'auto', - unfrequent: true, - item: { - system: '显示按钮', - menu: '打开菜单', - pause: '切换暂停', - auto: '切换托管', - chat: '显示聊天', - off: '关闭', - }, - onclick: function (item) { - if (get.is.nomenu('swipe_up', item)) return false; - game.saveConfig('swipe_up', item); - } - }, - swipe_left: { - name: '左划操作', - intro: '向左滑动时执行的操作', - init: 'system', - unfrequent: true, - item: { - system: '显示按钮', - menu: '打开菜单', - pause: '切换暂停', - auto: '切换托管', - chat: '显示聊天', - off: '关闭', - }, - onclick: function (item) { - if (get.is.nomenu('swipe_left', item)) return false; - game.saveConfig('swipe_left', item); - } - }, - swipe_right: { - name: '右划操作', - intro: '向右滑动时执行的操作', - init: 'system', - unfrequent: true, - item: { - system: '显示按钮', - menu: '打开菜单', - pause: '切换暂停', - auto: '切换托管', - chat: '显示聊天', - off: '关闭', - }, - onclick: function (item) { - if (get.is.nomenu('swipe_right', item)) return false; - game.saveConfig('swipe_right', item); - } - }, - round_menu_func: { - name: '触屏按钮操作', - intro: '点击屏幕中圆形按钮时执行的操作', - init: 'system', - unfrequent: true, - item: { - system: '显示按钮', - menu: '打开菜单', - pause: '切换暂停', - auto: '切换托管' - }, - onclick: function (item) { - if (get.is.nomenu('round_menu_func', item)) return false; - game.saveConfig('round_menu_func', item); - }, - }, - show_splash: { - name: '显示开始界面', - intro: '游戏开始前进入模式选择画面', - init: 'init', - item: { - off: '关闭', - init: '首次启动', - always: '保持开启', - } - }, - game_speed: { - name: '游戏速度', - init: 'mid', - item: { - vslow: '慢', - slow: '较慢', - mid: '中', - fast: '较快', - vfast: '快', - vvfast: '很快', - }, - intro: '设置不同游戏操作间的时间间隔' - }, - sync_speed: { - name: '限制结算速度', - intro: '在动画结算完成前不执行下一步操作,开启后游戏操作的间隔更长但画面更浏畅,在游戏较卡时建议开启', - init: true - }, - enable_vibrate: { - name: '开启震动', - intro: '回合开始时使手机震动', - init: false - }, - right_click: { - name: '右键操作', - init: 'pause', - intro: '在空白区域点击右键时的操作', - unfrequent: true, - item: { - pause: '暂停', - shortcut: '工具', - config: '选项', - auto: '托管', - }, - onclick: function (item) { - if (get.is.nomenu('right_click', item)) return false; - game.saveConfig('right_click', item); - } - }, - longpress_info: { - name: '长按显示信息', - init: true, - unfrequent: true, - restart: true, - intro: '长按后弹出菜单', - }, - right_info: { - name: '右键显示信息', - init: true, - unfrequent: true, - restart: true, - intro: '右键点击后弹出菜单', - }, - hover_all: { - name: '悬停显示信息', - init: true, - unfrequent: true, - restart: true, - intro: '悬停后弹出菜单', - }, - hover_handcard: { - name: '悬停手牌显示信息', - init: true, - unfrequent: true, - intro: '悬停手牌后弹出菜单', - }, - hoveration: { - name: '悬停菜单弹出时间', - unfrequent: true, - intro: '鼠标移至目标到弹出菜单的时间间隔', - init: '1000', - item: { - '500': '0.5秒', - '700': '0.7秒', - '1000': '1秒', - '1500': '1.5秒', - '2500': '2.5秒', - } - }, - doubleclick_intro: { - name: '双击显示武将资料', - init: true, - unfrequent: true, - intro: '双击武将头像后显示其资料卡', - }, - video: { - name: '保存录像', - init: '20', - intro: '游戏结束后保存录像在最大条数,超过后将从最早的录像开始删除(已收藏的录像不计入条数)', - item: { - '0': '关闭', - '5': '五局', - '10': '十局', - '20': '二十局', - '50': '五十局', - '10000': '无限', - }, - unfrequent: true, - }, - max_loadtime: { - name: '最长载入时间', - intro: '设置游戏从启动到完成载入所需的最长时间,超过此时间未完成载入会报错,若设备较慢或安装了较多扩展可适当延长此时间', - init: '5000', - unfrequent: true, - item: { - 5000: '5秒', - 10000: '10秒', - 20000: '20秒', - 60000: '60秒' - }, - onclick: function (item) { - game.saveConfig('max_loadtime', item); - if (item == '5000') { - localStorage.removeItem(lib.configprefix + 'loadtime'); - } - else { - localStorage.setItem(lib.configprefix + 'loadtime', item); - } - } - }, - mousewheel: { - name: '滚轮控制手牌', - init: true, - unfrequent: true, - intro: '开启后滚轮可使手牌横向滚动,在mac等可横向滚动的设备上建议关闭', - onclick: function (bool) { - game.saveConfig('mousewheel', bool); - if (lib.config.touchscreen) return; - if (lib.config.mousewheel) { - ui.handcards1Container.onmousewheel = ui.click.mousewheel; - ui.handcards2Container.onmousewheel = ui.click.mousewheel; - } - else { - ui.handcards1Container.onmousewheel = null; - ui.handcards2Container.onmousewheel = null; - } - } - }, - auto_check_update: { - name: '自动检查游戏更新', - intro: '进入游戏时检查更新', - init: false, - unfrequent: true - }, - lucky_star: { - name: '幸运星模式', - intro: '在涉及随机数等的技能中,必定得到效果最好的结果。(联机模式无效)', - init: false, - unfrequent: true - }, - dev: { - name: '开发者模式', - intro: '开启后可使用浏览器控制台控制游戏,同时可更新到开发版', - init: false, - onclick: function (bool) { - game.saveConfig('dev', bool); - if (_status.connectMode) return; - if (bool) { - lib.cheat.i(); - } - else { - delete window.cheat; - delete window.game; - delete window.ui; - delete window.get; - delete window.ai; - delete window.lib; - delete window._status; - } - }, - unfrequent: true, - }, - fuck_sojson: { - name: '检测加密扩展', - init: false, - }, - errstop: { - name: '出错时停止游戏', - init: false, - unfrequent: true - }, - update_link: { - name: '更新地址', - init: 'coding', - unfrequent: true, - item: { - coding: 'CSDN', - github: 'GitHub', - }, - onclick: function (item) { - game.saveConfig('update_link', item); - lib.updateURL = lib.updateURLS[item] || lib.updateURLS.coding; - }, - }, - extension_source: { - name: '获取扩展地址', - init: 'GitHub Proxy', - unfrequent: true, - item: {}, - intro: () => `获取在线扩展时的地址。当前地址:${document.createElement('br').outerHTML}${lib.config.extension_sources[lib.config.extension_source]}` - }, - extension_create: { - name: '添加获取扩展地址', - clear: true, - unfrequent: true, - onclick: function () { - game.prompt('请输入地址名称', function (str) { - if (str) { - var map = lib.config.extension_sources; - game.prompt('请输入' + str + '的地址', function (str2) { - if (str2) { - delete map[str]; - map[str] = str2; - game.saveConfig('extension_sources', map); - game.saveConfig('extension_source', str); - var nodexx = ui.extension_source; - nodexx.updateInner(); - var nodeyy = nodexx._link.menu; - var nodezz = nodexx._link.config; - for (var i = 0; i < nodeyy.childElementCount; i++) { - if (nodeyy.childNodes[i]._link == str) { - nodeyy.childNodes[i].remove(); - break; - } - } - var textMenu = ui.create.div('', str, nodeyy, function () { - var node = this.parentNode._link; - var config = node._link.config; - node._link.current = this.link; - var tmpName = node.lastChild.innerHTML; - node.lastChild.innerHTML = config.item[this._link]; - if (config.onclick) { - if (config.onclick.call(node, this._link, this) === false) { - node.lastChild.innerHTML = tmpName; - } - } - if (config.update) { - config.update(); - } - }); - textMenu._link = str; - nodezz.item[name] = str; - alert('已添加扩展地址:' + str); - } - }); - } - }); - }, - }, - extension_delete: { - name: '删除当前扩展地址', - clear: true, - unfrequent: true, - onclick: function () { - var bool = false, map = lib.config.extension_sources; - for (var i in map) { - if (i != lib.config.extension_source) { - bool = true; - break; - } - } - if (!bool) { - alert('不能删除最后一个扩展地址!'); - return; - } - var name = lib.config.extension_source; - game.saveConfig('extension_source', i); - delete map[name]; - game.saveConfig('extension_sources', map); - var nodexx = ui.extension_source; - nodexx.updateInner(); - var nodeyy = nodexx._link.menu; - var nodezz = nodexx._link.config; - for (var i = 0; i < nodeyy.childElementCount; i++) { - if (nodeyy.childNodes[i]._link == name) { - nodeyy.childNodes[i].remove(); - break; - } - } - delete nodezz.item[name]; - alert('已删除扩展地址:' + name); - }, - }, - update: function (config, map) { - if ('ontouchstart' in document) { - map.touchscreen.show(); - } - else { - map.touchscreen.hide(); - } - if (lib.device || lib.node) { - map.auto_check_update.show(); - } - else { - map.auto_check_update.hide(); - } - if (lib.device) { - map.enable_vibrate.show(); - map.keep_awake.show(); - } - else { - map.enable_vibrate.hide(); - map.keep_awake.hide(); - } - // if(config.enable_pressure){ - // map.pressure_click.show(); - // if(lib.device){ - // map.pressure_taptic.show(); - // } - // else{ - // map.pressure_taptic.hide(); - // } - // } - // else{ - // map.pressure_click.hide(); - // map.pressure_taptic.hide(); - // } - if (lib.config.touchscreen) { - map.mousewheel.hide(); - map.hover_all.hide(); - map.hover_handcard.hide(); - map.hoveration.hide(); - map.right_info.hide(); - map.right_click.hide(); - map.longpress_info.show(); - map.swipe.show(); - if (lib.config.swipe) { - map.swipe_up.show(); - map.swipe_down.show(); - map.swipe_left.show(); - map.swipe_right.show(); - } - else { - map.swipe_up.hide(); - map.swipe_down.hide(); - map.swipe_left.hide(); - map.swipe_right.hide(); - } - } - else { - map.mousewheel.show(); - map.hover_all.show(); - map.right_info.show(); - map.right_click.show(); - map.longpress_info.hide(); - if (!config.hover_all) { - map.hover_handcard.hide(); - map.hoveration.hide(); - } - else { - map.hover_handcard.show(); - map.hoveration.show(); - } - map.swipe.hide(); - map.swipe_up.hide(); - map.swipe_down.hide(); - map.swipe_left.hide(); - map.swipe_right.hide(); - } - if (lib.config.enable_drag) { - if (lib.config.touchscreen) { - map.enable_dragline.hide(); - map.enable_touchdragline.show(); - } - else { - map.enable_dragline.show(); - map.enable_touchdragline.hide(); - } - } - else { - map.enable_dragline.hide(); - map.enable_touchdragline.hide(); - } - if (!get.is.phoneLayout()) { - map.round_menu_func.hide(); - } - else { - map.round_menu_func.show(); - } - if (!lib.node && lib.device != 'ios') { - map.confirm_exit.show(); - } - else { - map.confirm_exit.hide(); - } - if (config.dev) { - map.errstop.show(); - } - else { - map.errstop.hide(); - } - } - } - }, - appearence: { - name: '外观', - config: { - theme: { - name: '主题', - init: 'woodden', - item: {}, - visualMenu: function (node, link) { - if (!node.menu) { - node.className = 'button character themebutton ' + link; - node.menu = ui.create.div(node, '', '
    '); - } - }, - onclick: async (theme) => { - game.saveConfig('theme', theme); - ui.arena.hide(); - lib.init.background(); - if (lib.config.autostyle) { - if (theme === "simple") { - lib.configMenu.appearence.config.player_border.onclick("slim"); - } - else { - lib.configMenu.appearence.config.player_border.onclick("normal"); - } - } - lib.announce.publish("Noname.Apperaence.Theme.onChanging", theme); - await new Promise(resolve => setTimeout(resolve, 500)); - - const deletingTheme = ui.css.theme; - ui.css.theme = lib.init.css(lib.assetURL + 'theme/' + lib.config.theme, 'style'); - deletingTheme.remove(); - lib.announce.publish("Noname.Apperaence.Theme.onChanged", theme); - await new Promise(resolve => setTimeout(resolve, 100)); - - ui.arena.show(); - lib.announce.publish("Noname.Apperaence.Theme.onChangeFinished", theme); - } - }, - layout: { - name: '布局', - init: 'mobile', - item: { - //default:'旧版', - newlayout: '对称', - mobile: '默认', - long: '宽屏', - long2: '手杀', - nova: '新版' - }, - visualMenu: function (node, link) { - node.className = 'button character themebutton ' + lib.config.theme; - if (!node.created) { - node.created = true; - node.style.overflow = 'hidden'; - node.firstChild.style.display = 'none'; - // node.firstChild.classList.add('shadowed'); - // node.firstChild.style.width='16px'; - // node.firstChild.style.height='auto'; - // node.firstChild.style.padding='2px'; - // node.firstChild.style.textAlign='center'; - var me = ui.create.div(node); - me.style.top = 'auto'; - if (link == 'default' || link == 'newlayout') { - me.style.width = 'calc(100% - 6px)'; - me.style.left = '3px'; - me.style.bottom = '3px'; - me.style.height = '25px'; - if (link == 'newlayout') { - me.style.height = '23px'; - me.style.bottom = '4px'; - } - } - else if (link == 'long2' || link == 'nova') { - me.style.display = 'none'; - } - else { - me.style.width = '120%'; - me.style.left = '-10%'; - me.style.bottom = '0'; - me.style.height = '22px'; - } - me.style.borderRadius = '2px'; - var list = ['re_caocao', 're_liubei', 'sp_zhangjiao', 'sunquan']; - for (var i = 0; i < 4; i++) { - var player = ui.create.div('.fakeplayer', node); - ui.create.div('.avatar', player).setBackground(list.randomRemove(), 'character'); - player.style.borderRadius = '2px'; - if (i != 3) { - player.style.top = 'auto'; - } - if (link == 'default') { - player.style.height = '19px'; - player.style.width = '38px'; - player.classList.add('oldlayout'); - } - else if (link == 'mobile' || link == 'newlayout') { - player.style.width = '24px'; - player.style.height = '29px'; - } - else if (link == 'nova') { - player.style.width = '20px'; - player.style.height = '24px'; - } - else { - player.style.width = '20px'; - player.style.height = '34px'; - } - if (i == 1) { - player.style.left = '3px'; - } - if (i == 2) { - player.style.left = 'auto'; - player.style.right = '3px'; - } - if (i == 3) { - player.style.top = '3px'; - } - if (link == 'default') { - if (i == 0) { - player.style.bottom = '6px'; - } - if (i == 0 || i == 3) { - player.style.left = 'calc(50% - 18px)'; - } - if (i == 1 || i == 2) { - player.style.bottom = '36px'; - } - } - else if (link == 'newlayout') { - if (i == 0) { - player.style.bottom = '1px'; - } - if (i == 0 || i == 3) { - player.style.left = 'calc(50% - 12px)'; - } - if (i == 1 || i == 2) { - player.style.bottom = '32px'; - } - } - else if (link == 'mobile') { - if (i == 0 || i == 3) { - player.style.left = 'calc(50% - 12px)'; - } - if (i == 1 || i == 2) { - player.style.bottom = '30px'; - } - } - else if (link == 'long') { - if (i == 0 || i == 3) { - player.style.left = 'calc(50% - 10px)'; - } - if (i == 1 || i == 2) { - player.style.bottom = '45px'; - } - } - else if (link == 'long2') { - if (i == 0) { - player.style.bottom = '2px'; - player.style.left = '3px'; - } - if (i == 3) { - player.style.left = 'calc(50% - 10px)'; - } - if (i == 1 || i == 2) { - player.style.bottom = '45px'; - } - } - else if (link == 'nova') { - if (i == 0) { - player.style.bottom = '2px'; - player.style.left = '3px'; - } - if (i == 3) { - player.style.left = 'calc(50% - 10px)'; - } - if (i == 1 || i == 2) { - player.style.left = '3px'; - player.style.bottom = (i * 30) + 'px'; - } - } - - if (i == 0 && (link == 'mobile' || link == 'long')) { - player.classList.add('me'); - player.style.borderRadius = '0px'; - player.style.width = '25px'; - player.style.height = '25px'; - player.style.bottom = '-3px'; - player.style.left = '-3px'; - } - } - } - }, - onclick: function (layout) { - if (lib.layoutfixed.includes(lib.config.mode)) { - game.saveConfig('layout', layout); - } - else { - lib.init.layout(layout); - } - } - }, - splash_style: { - name: '启动页', - init: 'style1', - item: { - style1: '样式一', - style2: '样式二', - }, - visualMenu: (node, link) => { - node.className = 'button character'; - node.style.width = '200px'; - node.style.height = `${node.offsetWidth * 1080 / 2400}px`; - node.style.display = 'flex'; - node.style.flexDirection = 'column'; - node.style.alignItems = 'center'; - node.style.backgroundSize = '100% 100%'; - node.setBackgroundImage(`image/splash/${link}.jpg`); - } - }, - // fewplayer:{ - // name:'启用人数', - // intro:'设置启用新版布局的最小人数(不足时切换至默认布局)', - // init:'3', - // // unfrequent:true, - // item:{ - // '2':'两人', - // '3':'三人', - // '4':'四人', - // '5':'五人', - // '6':'六人', - // '7':'七人', - // '8':'八人', - // }, - // onclick:function(item){ - // game.saveConfig('fewplayer',item); - // if(ui.arena) ui.arena.setNumber(ui.arena.dataset.number); - // } - // }, - player_height: { - name: '角色高度', - init: 'long', - // unfrequent:true, - item: { - short: '矮', - default: '中', - long: '高', - }, - onclick: function (item) { - game.saveConfig('player_height', item); - ui.arena.dataset.player_height = item; - } - }, - player_height_nova: { - name: '角色高度', - init: 'short', - item: { - // auto:'自动', - short: '矮', - default: '中', - long: '高', - }, - onclick: function (item) { - game.saveConfig('player_height_nova', item); - // if(item=='auto'){ - // if(parseInt(ui.arena.dataset.number)>=7){ - // ui.arena.dataset.player_height_nova='short'; - // } - // else{ - // ui.arena.dataset.player_height_nova='default'; - // } - // } - // else{ - ui.arena.dataset.player_height_nova = item; - // } - } - }, - // background_color_music:{ - // name:'背景色', - // init:'black', - // item:{ - // blue:'蓝色', - // black:'黑色', - // }, - // onclick:function(color){ - // game.saveConfig('background_color_music',color); - // document.body.dataset.background_color_music=color; - // } - // }, - // background_color_wood:{ - // name:'背景色', - // init:'blue', - // item:{ - // blue:'蓝色', - // black:'黑色', - // }, - // onclick:function(color){ - // game.saveConfig('background_color_wood',color); - // document.body.dataset.background_color_wood=color; - // } - // }, - // theme_color_music:{ - // name:'主题色', - // init:'black', - // item:{ - // blue:'蓝色', - // black:'黑色', - // }, - // onclick:function(color){ - // game.saveConfig('theme_color_music',color); - // document.body.dataset.theme_color_music=color; - // } - // }, - ui_zoom: { - name: '界面缩放', - unfrequent: true, - init: 'normal', - item: { - esmall: '80%', - vsmall: '90%', - small: '95%', - normal: '100%', - big: '105%', - vbig: '110%', - ebig: '120%', - eebig: '150%', - eeebig: '180%', - eeeebig: '200%', - }, - onclick: function (zoom) { - game.saveConfig('ui_zoom', zoom); - switch (zoom) { - case 'esmall': zoom = 0.8; break; - case 'vsmall': zoom = 0.9; break; - case 'small': zoom = 0.93; break; - case 'big': zoom = 1.05; break; - case 'vbig': zoom = 1.1; break; - case 'ebig': zoom = 1.2; break; - case 'eebig': zoom = 1.5; break; - case 'eeebig': zoom = 1.8; break; - case 'eeeebig': zoom = 2; break; - default: zoom = 1; - } - game.documentZoom = game.deviceZoom * zoom; - ui.updatez(); - if (Array.isArray(lib.onresize)) { - lib.onresize.forEach(fun => { - if (typeof fun == 'function') fun(); - }); - } - } - }, - image_background: { - name: '游戏背景', - init: 'default', - item: {}, - visualBar: function (node, item, create) { - if (node.created) { - node.lastChild.classList.remove('active'); - return; - } - node.created = true; - ui.create.filediv('.menubutton', '添加背景', node, function (file) { - if (file) { - var name = file.name; - if (name.includes('.')) { - name = name.slice(0, name.indexOf('.')); - } - var link = (game.writeFile ? 'cdv_' : 'custom_') + name; - if (item[link]) { - for (var i = 1; i < 1000; i++) { - if (!item[link + '_' + i]) { - link = link + '_' + i; break; - } - } - } - item[link] = name; - var callback = function () { - create(link, node.parentNode.defaultNode); - node.parentNode.updateBr(); - lib.config.customBackgroundPack.add(link); - game.saveConfig('customBackgroundPack', lib.config.customBackgroundPack); - }; - if (game.writeFile) { - game.writeFile(file, 'image/background', link + '.jpg', callback); - } - else { - game.putDB('image', link, file, callback); - } - if (node.lastChild.classList.contains('active')) { - editbg.call(node.lastChild); - } - } - }).inputNode.accept = 'image/*'; - var editbg = function () { - this.classList.toggle('active'); - var page = this.parentNode.parentNode; - for (var i = 0; i < page.childElementCount; i++) { - if (page.childNodes[i].classList.contains('button')) { - var link = page.childNodes[i]._link; - if (link && link != 'default') { - var str; - if (this.classList.contains('active')) { - if (link.startsWith('custom_') || link.startsWith('cdv_')) { - str = '删除'; - } - else { - str = '隐藏'; - } - } - else { - str = item[link]; - } - page.childNodes[i].firstChild.innerHTML = get.verticalStr(str); - } - } - } - }; - ui.create.div('.menubutton', '编辑背景', node, editbg); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button character'; - node.style.backgroundImage = ''; - node.style.backgroundSize = ''; - if (node.firstChild) { - node.firstChild.innerHTML = get.verticalStr(name); - } - if (link == 'default' || link.startsWith('custom_')) { - node.style.backgroundImage = 'none'; - node.classList.add('dashedmenubutton'); - if (link.startsWith('custom_')) { - game.getDB('image', link, function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.style.backgroundSize = 'cover'; - node.classList.remove('dashedmenubutton'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - else { - node.parentNode.defaultNode = node; - } - } - else { - node.setBackgroundImage('image/background/' + link + '.jpg'); - node.style.backgroundSize = 'cover'; - } - }, - onclick: function (background, node) { - if (node && node.firstChild) { - var menu = node.parentNode; - if (node.firstChild.innerHTML == get.verticalStr('隐藏')) { - menu.parentNode.noclose = true; - node.remove(); - menu.updateBr(); - if (!lib.config.prompt_hidebg) { - alert('隐藏的背景可通过选项-其它-重置隐藏内容恢复'); - game.saveConfig('prompt_hidebg', true); - } - lib.config.hiddenBackgroundPack.add(background); - game.saveConfig('hiddenBackgroundPack', lib.config.hiddenBackgroundPack); - delete lib.configMenu.appearence.config.image_background.item[background]; - if (lib.config.image_background == background) { - background = 'default'; - this.lastChild.innerHTML = '默认'; - } - else { - this.lastChild.innerHTML = lib.configMenu.appearence.config.image_background.item[lib.config.image_background]; - return; - } - } - else if (node.firstChild.innerHTML == get.verticalStr('删除')) { - menu.parentNode.noclose = true; - if (confirm('是否删除此背景?(此操作不可撤销)')) { - node.remove(); - menu.updateBr(); - lib.config.customBackgroundPack.remove(background); - game.saveConfig('customBackgroundPack', lib.config.customBackgroundPack); - if (background.startsWith('cdv_')) { - game.removeFile('image/background/' + background + '.jpg'); - } - else { - game.deleteDB('image', background); - } - delete lib.configMenu.appearence.config.image_background.item[background]; - if (lib.config.image_background == background) { - background = 'default'; - this.lastChild.innerHTML = '默认'; - } - else { - this.lastChild.innerHTML = lib.configMenu.appearence.config.image_background.item[lib.config.image_background]; - return; - } - } - } - } - game.saveConfig('image_background', background); - lib.init.background(); - game.updateBackground(); - }, - }, - image_background_random: { - name: '随机背景', - init: false, - onclick: function (bool) { - game.saveConfig('image_background_random', bool); - lib.init.background(); - } - }, - image_background_blur: { - name: '背景模糊', - init: false, - onclick: function (bool) { - game.saveConfig('image_background_blur', bool); - if (lib.config.image_background_blur) { - ui.background.style.filter = 'blur(8px)'; - ui.background.style.webkitFilter = 'blur(8px)'; - ui.background.style.transform = 'scale(1.05)'; - } - else { - ui.background.style.filter = ''; - ui.background.style.webkitFilter = ''; - ui.background.style.transform = ''; - } - }, - }, - phonelayout: { - name: '触屏布局', - init: false, - onclick: function (bool) { - if (get.is.nomenu('phonelayout', bool)) return false; - game.saveConfig('phonelayout', bool); - if (get.is.phoneLayout()) { - ui.css.phone.href = lib.assetURL + 'layout/default/phone.css'; - ui.arena.classList.add('phone'); - } - else { - ui.css.phone.href = ''; - ui.arena.classList.remove('phone'); - } - } - }, - change_skin: { - name: '开启换肤', - init: true, - intro: '在武将的右键菜单中换肤,皮肤可在选项-文件-图片文件-皮肤图片中添加' - }, - change_skin_auto: { - name: '自动换肤', - init: 'off', - item: { - 'off': '关闭', - '30000': '半分钟', - '60000': '一分钟', - '120000': '两分钟', - '300000': '五分钟', - }, - intro: '游戏每进行一段时间自动为一个随机角色更换皮肤', - onclick: function (item) { - game.saveConfig('change_skin_auto', item); - clearTimeout(_status.skintimeout); - if (item != 'off') { - _status.skintimeout = setTimeout(ui.click.autoskin, parseInt(item)); - } - } - }, - card_style: { - name: '卡牌样式', - init: 'default', - intro: '设置正面朝上的卡牌的样式', - item: { - wood: '木纹', - music: '音乐', - simple: '原版', - ol: '手杀', - // new:'新版', - custom: '自定', - default: '默认', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton', '添加图片', node, function (file) { - if (file) { - game.putDB('image', 'card_style', file, function () { - game.getDB('image', 'card_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.style.backgroundImage = 'url(' + data + ')'; - button.className = 'button card fullskin'; - node.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'card_style'); - button.style.backgroundImage = 'none'; - button.className = 'button character dashedmenubutton'; - node.classList.remove('showdelete'); - if (lib.config.card_style == 'custom') { - lib.configMenu.appearence.config.card_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - } - }); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button card fullskin'; - node.style.backgroundSize = '100% 100%'; - switch (link) { - case 'default': case 'custom': { - if (lib.config.theme == 'simple') { - node.style.backgroundImage = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))'; - node.className = 'button character'; - } - else { - node.style.backgroundImage = 'none'; - node.className = 'button character dashedmenubutton'; - } - break; - } - case 'new': node.setBackgroundImage('theme/style/card/image/new.png'); break; - case 'ol': node.setBackgroundImage('theme/style/card/image/ol.png'); break; - case 'wood': node.setBackgroundImage('theme/woodden/wood.jpg'); node.style.backgroundSize = 'initial'; break; - case 'music': node.setBackgroundImage('theme/music/wood3.png'); break; - case 'simple': node.setBackgroundImage('theme/simple/card.png'); break; - } - if (link == 'custom') { - node.classList.add('transparent'); - game.getDB('image', 'card_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.className = 'button card fullskin'; - node.parentNode.lastChild.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - onclick: function (layout) { - game.saveConfig('card_style', layout); - var style = ui.css.card_style; - ui.css.card_style = lib.init.css(lib.assetURL + 'theme/style/card', lib.config.card_style); - style.remove(); - if (ui.css.card_stylesheet) { - ui.css.card_stylesheet.remove(); - delete ui.css.card_stylesheet; - } - if (layout == 'custom') { - game.getDB('image', 'card_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.card_stylesheet) { - ui.css.card_stylesheet.remove(); - } - ui.css.card_stylesheet = lib.init.sheet('.card:not(*:empty){background-image:url(' + fileLoadedEvent.target.result + ')}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - unfrequent: true, - }, - cardback_style: { - name: '卡背样式', - intro: '设置背面朝上的卡牌的样式', - init: 'default', - item: { - // wood:'木纹', - // music:'音乐', - official: '原版', - // new:'新版', - feicheng: '废城', - liusha: '流沙', - ol: '手杀', - custom: '自定', - default: '默认', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton', '添加图片', node, function (file) { - if (file) { - game.putDB('image', 'cardback_style', file, function () { - game.getDB('image', 'cardback_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.style.backgroundImage = 'url(' + data + ')'; - button.className = 'button character'; - node.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image/*'; - ui.create.filediv('.menubutton.deletebutton.addbutton', '添加翻转图片', node, function (file) { - if (file) { - game.putDB('image', 'cardback_style2', file, function () { - node.classList.add('hideadd'); - }); - } - }).inputNode.accept = 'image/*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'cardback_style'); - game.deleteDB('image', 'cardback_style2'); - button.style.backgroundImage = 'none'; - button.className = 'button character dashedmenubutton'; - node.classList.remove('showdelete'); - node.classList.remove('hideadd'); - if (lib.config.cardback_style == 'custom') { - lib.configMenu.appearence.config.cardback_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - } - }); - }, - visualMenu: function (node, link, name, config) { - node.style.backgroundSize = '100% 100%'; - switch (link) { - case 'default': case 'custom': { - node.style.backgroundImage = 'none'; - node.className = 'button character dashedmenubutton'; - break; - } - case 'new': node.className = 'button character'; node.setBackgroundImage('theme/style/cardback/image/new.png'); break; - case 'feicheng': node.className = 'button character'; node.setBackgroundImage('theme/style/cardback/image/feicheng.png'); break; - case 'official': node.className = 'button character'; node.setBackgroundImage('theme/style/cardback/image/official.png'); break; - case 'liusha': node.className = 'button character'; node.setBackgroundImage('theme/style/cardback/image/liusha.png'); break; - case 'ol': node.className = 'button character'; node.setBackgroundImage('theme/style/cardback/image/ol.png'); break; - case 'wood': node.className = 'button card fullskin'; node.setBackgroundImage('theme/woodden/wood.jpg'); node.style.backgroundSize = 'initial'; break; - case 'music': node.className = 'button card fullskin'; node.setBackgroundImage('theme/music/wood3.png'); break; - } - if (link == 'custom') { - node.classList.add('transparent'); - game.getDB('image', 'cardback_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.className = 'button character'; - node.parentNode.lastChild.classList.add('showdelete'); - game.getDB('image', 'cardback_style2', function (file) { - if (file) { - node.parentNode.lastChild.classList.add('hideadd'); - } - }); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - onclick: function (layout) { - game.saveConfig('cardback_style', layout); - var style = ui.css.cardback_style; - ui.css.cardback_style = lib.init.css(lib.assetURL + 'theme/style/cardback', lib.config.cardback_style); - style.remove(); - if (ui.css.cardback_stylesheet) { - ui.css.cardback_stylesheet.remove(); - delete ui.css.cardback_stylesheet; - } - if (ui.css.cardback_stylesheet2) { - ui.css.cardback_stylesheet2.remove(); - delete ui.css.cardback_stylesheet2; - } - if (layout == 'custom') { - game.getDB('image', 'cardback_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.cardback_stylesheet) { - ui.css.cardback_stylesheet.remove(); - } - ui.css.cardback_stylesheet = lib.init.sheet('.card:empty,.card.infohidden{background-image:url(' + fileLoadedEvent.target.result + ')}'); - game.getDB('image', 'cardback_style2', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.cardback_stylesheet2) { - ui.css.cardback_stylesheet2.remove(); - } - ui.css.cardback_stylesheet2 = lib.init.sheet('.card.infohidden:not(.infoflip){background-image:url(' + fileLoadedEvent.target.result + ')}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - unfrequent: true, - }, - hp_style: { - name: '体力条样式', - init: 'ol', - item: { - default: '默认', - // official:'勾玉', - emotion: '表情', - glass: '勾玉', - round: '国战', - ol: '手杀', - xinglass: '双鱼', - xinround: 'OL', - custom: '自定', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton.addbutton', '添加图片', node, function (file) { - if (file && node.currentDB) { - game.putDB('image', 'hp_style' + node.currentDB, file, function () { - game.getDB('image', 'hp_style' + node.currentDB, function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.childNodes[node.currentDB - 1].style.backgroundImage = 'url(' + data + ')'; - button.classList.add('shown'); - node.classList.add('showdelete'); - node.currentDB++; - if (node.currentDB > 4) { - node.classList.add('hideadd'); - button.classList.remove('transparent'); - delete node.currentDB; - } - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image/*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'hp_style1'); - game.deleteDB('image', 'hp_style2'); - game.deleteDB('image', 'hp_style3'); - game.deleteDB('image', 'hp_style4'); - for (var i = 0; i < button.childElementCount; i++) { - button.childNodes[i].style.backgroundImage = 'none'; - } - node.classList.remove('showdelete'); - node.classList.remove('hideadd'); - if (lib.config.hp_style == 'custom') { - lib.configMenu.appearence.config.hp_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - button.classList.remove('shown'); - node.currentDB = 1; - } - }); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button hpbutton dashedmenubutton'; - node.innerHTML = ''; - for (var i = 1; i <= 4; i++) { - var div = ui.create.div(node); - if (link == 'default') { - ui.create.div(div); - } - else if (link != 'custom') { - div.setBackgroundImage('theme/style/hp/image/' + link + i + '.png'); - } - if (i == 4) { - div.style.webkitFilter = 'grayscale(1)'; - } - } - if (link == 'custom') { - node.classList.add('transparent'); - var getDB = function (num) { - node.parentNode.lastChild.currentDB = num; - game.getDB('image', 'hp_style' + num, function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.childNodes[num - 1].style.backgroundImage = 'url(' + data + ')'; - node.classList.add('shown'); - node.parentNode.lastChild.classList.add('showdelete'); - if (num < 4) { - getDB(num + 1); - } - else { - node.parentNode.lastChild.classList.add('hideadd'); - node.classList.remove('transparent'); - delete node.parentNode.firstChild.currentDB; - } - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }; - getDB(1); - } - }, - onclick: function (layout) { - game.saveConfig('hp_style', layout); - var style = ui.css.hp_style; - ui.css.hp_style = lib.init.css(lib.assetURL + 'theme/style/hp', lib.config.hp_style); - style.remove(); - if (ui.css.hp_stylesheet1) { - ui.css.hp_stylesheet1.remove(); - delete ui.css.hp_stylesheet1; - } - if (ui.css.hp_stylesheet2) { - ui.css.hp_stylesheet2.remove(); - delete ui.css.hp_stylesheet2; - } - if (ui.css.hp_stylesheet3) { - ui.css.hp_stylesheet3.remove(); - delete ui.css.hp_stylesheet3; - } - if (ui.css.hp_stylesheet4) { - ui.css.hp_stylesheet4.remove(); - delete ui.css.hp_stylesheet4; - } - if (layout == 'custom') { - game.getDB('image', 'hp_style1', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.hp_stylesheet1) { - ui.css.hp_stylesheet1.remove(); - } - ui.css.hp_stylesheet1 = lib.init.sheet('.hp:not(.text):not(.actcount)[data-condition="high"]>div:not(.lost){background-image:url(' + fileLoadedEvent.target.result + ')}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - game.getDB('image', 'hp_style2', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.hp_stylesheet2) { - ui.css.hp_stylesheet2.remove(); - } - ui.css.hp_stylesheet2 = lib.init.sheet('.hp:not(.text):not(.actcount)[data-condition="mid"]>div:not(.lost){background-image:url(' + fileLoadedEvent.target.result + ')}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - game.getDB('image', 'hp_style3', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.hp_stylesheet3) { - ui.css.hp_stylesheet3.remove(); - } - ui.css.hp_stylesheet3 = lib.init.sheet('.hp:not(.text):not(.actcount)[data-condition="low"]>div:not(.lost){background-image:url(' + fileLoadedEvent.target.result + ')}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - game.getDB('image', 'hp_style4', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.hp_stylesheet4) { - ui.css.hp_stylesheet4.remove(); - } - ui.css.hp_stylesheet4 = lib.init.sheet('.hp:not(.text):not(.actcount)>.lost{background-image:url(' + fileLoadedEvent.target.result + ')}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - unfrequent: true, - }, - player_style: { - name: '角色背景', - init: 'default', - intro: '设置角色的背景图片', - item: { - wood: '木纹', - music: '音乐', - simple: '简约', - custom: '自定', - default: '默认', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton', '添加图片', node, function (file) { - if (file) { - game.putDB('image', 'player_style', file, function () { - game.getDB('image', 'player_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.style.backgroundImage = 'url(' + data + ')'; - button.className = 'button character'; - button.style.backgroundSize = '100% 100%'; - node.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image/*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'player_style'); - button.style.backgroundImage = 'none'; - button.className = 'button character dashedmenubutton'; - node.classList.remove('showdelete'); - if (lib.config.player_style == 'custom') { - lib.configMenu.appearence.config.player_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - } - }); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button character'; - node.style.backgroundSize = ''; - node.style.height = '108px'; - switch (link) { - case 'default': case 'custom': { - node.style.backgroundImage = 'none'; - node.className = 'button character dashedmenubutton'; - break; - } - case 'wood': node.setBackgroundImage('theme/woodden/wood.jpg'); break; - case 'music': node.style.backgroundImage = 'linear-gradient(#4b4b4b, #464646)'; break; - case 'simple': node.style.backgroundImage = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))'; break; - } - if (link == 'custom') { - node.classList.add('transparent'); - game.getDB('image', 'player_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.className = 'button character'; - node.parentNode.lastChild.classList.add('showdelete'); - node.style.backgroundSize = '100% 100%'; - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - onclick: function (layout) { - game.saveConfig('player_style', layout); - if (ui.css.player_stylesheet) { - ui.css.player_stylesheet.remove(); - delete ui.css.player_stylesheet; - } - if (layout == 'custom') { - game.getDB('image', 'player_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.player_stylesheet) { - ui.css.player_stylesheet.remove(); - } - ui.css.player_stylesheet = lib.init.sheet('#window .player{background-image:url("' + fileLoadedEvent.target.result + '");background-size:100% 100%;}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - else if (layout != 'default') { - var str = ''; - switch (layout) { - case 'wood': str = 'url("' + lib.assetURL + 'theme/woodden/wood.jpg")'; break; - case 'music': str = 'linear-gradient(#4b4b4b, #464646)'; break; - case 'simple': str = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))'; break; - } - ui.css.player_stylesheet = lib.init.sheet('#window .player{background-image:' + str + '}'); - } - }, - unfrequent: true, - }, - border_style: { - name: '角色边框', - init: 'default', - intro: '设置角色边框的样式,当设为自动时,样式将随着一局游戏中伤害或击杀的数量自动改变', - item: { - gold: '金框', - silver: '银框', - bronze: '铜框', - dragon_gold: '金龙', - dragon_silver: '银龙', - dragon_bronze: '玉龙', - custom: '自定', - auto: '自动', - default: '默认', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton', '添加图片', node, function (file) { - if (file) { - game.putDB('image', 'border_style', file, function () { - game.getDB('image', 'border_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.style.backgroundImage = 'url(' + data + ')'; - button.className = 'button character'; - button.style.backgroundSize = '100% 100%'; - node.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image/*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'border_style'); - button.style.backgroundImage = 'none'; - button.className = 'button character dashedmenubutton'; - node.classList.remove('showdelete'); - if (lib.config.border_style == 'custom') { - lib.configMenu.appearence.config.border_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - } - }); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button character'; - node.style.backgroundSize = ''; - node.style.height = '108px'; - node.dataset.decoration = ''; - if (link == 'default' || link == 'custom' || link == 'auto') { - node.style.backgroundImage = 'none'; - node.className = 'button character dashedmenubutton'; - } - else { - if (link.startsWith('dragon_')) { - link = link.slice(7); - node.dataset.decoration = link; - } - node.setBackgroundImage('theme/style/player/' + link + '1.png'); - node.style.backgroundSize = '100% 100%'; - } - if (link == 'custom') { - node.classList.add('transparent'); - game.getDB('image', 'border_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.className = 'button character'; - node.parentNode.lastChild.classList.add('showdelete'); - node.style.backgroundSize = '100% 100%'; - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - onclick: function (layout) { - game.saveConfig('border_style', layout); - if (ui.css.border_stylesheet) { - ui.css.border_stylesheet.remove(); - delete ui.css.border_stylesheet; - } - if (layout == 'custom') { - game.getDB('image', 'border_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.border_stylesheet) { - ui.css.border_stylesheet.remove(); - } - ui.css.border_stylesheet = lib.init.sheet(); - ui.css.border_stylesheet.id = "ui.css.border"; - ui.css.border_stylesheet.sheet.insertRule('#window .player>.framebg{display:block;background-image:url("' + fileLoadedEvent.target.result + '")}', 0); - ui.css.border_stylesheet.sheet.insertRule('.player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}', 0); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - else if (layout != 'default' && layout != 'auto') { - ui.css.border_stylesheet = lib.init.sheet(); - if (layout.startsWith('dragon_')) { - layout = layout.slice(7); - ui.arena.dataset.framedecoration = layout; - } - else { - ui.arena.dataset.framedecoration = ''; - } - ui.css.border_stylesheet.sheet.insertRule('#window .player>.framebg,#window #arena.long.mobile:not(.fewplayer) .player[data-position="0"]>.framebg{display:block;background-image:url("' + lib.assetURL + 'theme/style/player/' + layout + '1.png")}', 0); - ui.css.border_stylesheet.sheet.insertRule('#window #arena.long:not(.fewplayer) .player>.framebg, #arena.oldlayout .player>.framebg{background-image:url("' + lib.assetURL + 'theme/style/player/' + layout + '3.png")}', 0); - ui.css.border_stylesheet.sheet.insertRule('.player>.count{z-index: 3 !important;border-radius: 2px !important;text-align: center !important;}', 0); - } - }, - unfrequent: true, - }, - autoborder_count: { - name: '边框升级方式', - intro: '击杀 每击杀一人,边框提升两级
    伤害 每造成两点伤害,边框提升一级
    混合 击杀量决定边框颜色,伤害量决定边框装饰', - init: 'kill', - item: { - kill: '击杀', - damage: '伤害', - mix: '混合', - }, - unfrequent: true, - }, - autoborder_start: { - name: '基础边框颜色', - init: 'bronze', - item: { - bronze: '铜', - silver: '银', - gold: '金' - }, - unfrequent: true - }, - player_border: { - name: '边框宽度', - init: 'normal', - intro: '设置角色的边框宽度', - unfrequent: true, - item: { - slim: '细', - narrow: '窄', - normal: '中', - wide: '宽' - }, - onclick: function (item) { - game.saveConfig('player_border', item); - if (item != 'wide' || game.layout == 'long' || game.layout == 'long2') { - ui.arena.classList.add('slim_player'); - } - else { - ui.arena.classList.remove('slim_player'); - } - if (item == 'slim') { - ui.arena.classList.add('uslim_player'); - } - else { - ui.arena.classList.remove('uslim_player'); - } - if (item == 'narrow') { - ui.arena.classList.add('mslim_player'); - } - else { - ui.arena.classList.remove('mslim_player'); - } - if (item == 'normal' && lib.config.mode != 'brawl' && (game.layout == 'long' || game.layout == 'long2')) { - ui.arena.classList.add('lslim_player'); - } - else { - ui.arena.classList.remove('lslim_player'); - } - ui.window.dataset.player_border = item; - } - }, - menu_style: { - name: '菜单背景', - init: 'default', - item: { - wood: '木纹', - music: '音乐', - simple: '简约', - custom: '自定', - default: '默认', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton', '添加图片', node, function (file) { - if (file) { - game.putDB('image', 'menu_style', file, function () { - game.getDB('image', 'menu_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.style.backgroundImage = 'url(' + data + ')'; - button.style.backgroundSize = 'cover'; - button.className = 'button character'; - node.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image/*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'menu_style'); - button.style.backgroundImage = 'none'; - button.style.backgroundSize = 'auto'; - button.className = 'button character dashedmenubutton'; - node.classList.remove('showdelete'); - if (lib.config.menu_style == 'custom') { - lib.configMenu.appearence.config.menu_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - } - }); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button character'; - node.style.backgroundSize = 'auto'; - switch (link) { - case 'default': case 'custom': { - node.style.backgroundImage = 'none'; - node.classList.add('dashedmenubutton'); - break; - } - case 'wood': node.setBackgroundImage('theme/woodden/wood2.png'); break; - case 'music': node.style.backgroundImage = 'linear-gradient(#4b4b4b, #464646)'; break; - case 'simple': node.style.backgroundImage = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))'; break; - } - if (link == 'custom') { - node.classList.add('transparent'); - game.getDB('image', 'menu_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.style.backgroundSize = 'cover'; - node.className = 'button character'; - node.parentNode.lastChild.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - onclick: function (layout) { - game.saveConfig('menu_style', layout); - if (ui.css.menu_stylesheet) { - ui.css.menu_stylesheet.remove(); - delete ui.css.menu_stylesheet; - } - if (layout == 'custom') { - game.getDB('image', 'menu_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.menu_stylesheet) { - ui.css.menu_stylesheet.remove(); - } - ui.css.menu_stylesheet = lib.init.sheet('html #window>.dialog.popped,html .menu,html .menubg{background-image:url("' + fileLoadedEvent.target.result + '");background-size:cover}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - else if (layout != 'default') { - var str = ''; - switch (layout) { - case 'wood': str = 'url("' + lib.assetURL + 'theme/woodden/wood2.png")'; break; - case 'music': str = 'linear-gradient(#4b4b4b, #464646);color:white;text-shadow:black 0 0 2px'; break; - case 'simple': str = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));color:white;text-shadow:black 0 0 2px'; break; - } - ui.css.menu_stylesheet = lib.init.sheet('html #window>.dialog.popped,html .menu,html .menubg{background-image:' + str + '}'); - } - }, - unfrequent: true, - }, - control_style: { - name: '按钮背景', - init: 'default', - item: { - wood: '木纹', - music: '音乐', - simple: '简约', - custom: '自定', - default: '默认', - }, - visualBar: function (node, item, create, switcher) { - if (node.created) { - return; - } - var button; - for (var i = 0; i < node.parentNode.childElementCount; i++) { - if (node.parentNode.childNodes[i]._link == 'custom') { - button = node.parentNode.childNodes[i]; - } - } - if (!button) { - return; - } - node.created = true; - var deletepic; - ui.create.filediv('.menubutton', '添加图片', node, function (file) { - if (file) { - game.putDB('image', 'control_style', file, function () { - game.getDB('image', 'control_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - button.style.backgroundImage = 'url(' + data + ')'; - button.className = 'button character controlbutton'; - node.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - }); - } - }).inputNode.accept = 'image/*'; - deletepic = ui.create.div('.menubutton.deletebutton', '删除图片', node, function () { - if (confirm('确定删除自定义图片?(此操作不可撤销)')) { - game.deleteDB('image', 'control_style'); - button.style.backgroundImage = 'none'; - button.className = 'button character controlbutton dashedmenubutton'; - node.classList.remove('showdelete'); - if (lib.config.control_style == 'custom') { - lib.configMenu.appearence.config.control_style.onclick('default'); - switcher.lastChild.innerHTML = '默认'; - } - button.classList.add('transparent'); - } - }); - }, - visualMenu: function (node, link, name, config) { - node.className = 'button character controlbutton'; - node.style.backgroundSize = ''; - switch (link) { - case 'default': case 'custom': { - node.style.backgroundImage = 'none'; - node.classList.add('dashedmenubutton'); - break; - } - case 'wood': node.setBackgroundImage('theme/woodden/wood.jpg'); break; - case 'music': node.style.backgroundImage = 'linear-gradient(#4b4b4b, #464646)'; break; - case 'simple': node.style.backgroundImage = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4))'; break; - } - if (link == 'custom') { - node.classList.add('transparent'); - game.getDB('image', 'control_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - var data = fileLoadedEvent.target.result; - node.style.backgroundImage = 'url(' + data + ')'; - node.className = 'button character controlbutton'; - node.parentNode.lastChild.classList.add('showdelete'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - }, - onclick: function (layout) { - game.saveConfig('control_style', layout); - if (ui.css.control_stylesheet) { - ui.css.control_stylesheet.remove(); - delete ui.css.control_stylesheet; - } - if (layout == 'custom') { - game.getDB('image', 'control_style', function (fileToLoad) { - if (!fileToLoad) return; - var fileReader = new FileReader(); - fileReader.onload = function (fileLoadedEvent) { - if (ui.css.control_stylesheet) { - ui.css.control_stylesheet.remove(); - } - ui.css.control_stylesheet = lib.init.sheet('#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:url("' + fileLoadedEvent.target.result + '")}'); - }; - fileReader.readAsDataURL(fileToLoad, "UTF-8"); - }); - } - else if (layout != 'default') { - var str = ''; - switch (layout) { - case 'wood': str = 'url("' + lib.assetURL + 'theme/woodden/wood.jpg")'; break; - case 'music': str = 'linear-gradient(#4b4b4b, #464646);color:white;text-shadow:black 0 0 2px'; break; - case 'simple': str = 'linear-gradient(rgba(0,0,0,0.4), rgba(0,0,0,0.4));color:white;text-shadow:black 0 0 2px'; break; - } - if (layout == 'wood') { - ui.css.control_stylesheet = lib.init.sheet('#window .control,#window .menubutton,#window #system>div>div,#window #system>div>.pressdown2{background-image:' + str + '}'); - } - else { - ui.css.control_stylesheet = lib.init.sheet('#window .control,.menubutton:not(.active):not(.highlight):not(.red):not(.blue),#window #system>div>div{background-image:' + str + '}'); - } - } - }, - unfrequent: true, - }, - custom_button: { - name: '自定义按钮高度', - init: false, - unfrequent: true, - onclick: function (bool) { - if (bool !== 'skip') { - game.saveConfig('custom_button', bool); - } - if (ui.css.buttonsheet) { - ui.css.buttonsheet.remove(); - } - if (lib.config.custom_button) { - var cbnum1 = 6 + (parseInt(lib.config.custom_button_system_top) || 0); - var cbnum2 = 6 + (parseInt(lib.config.custom_button_system_bottom) || 0); - var cbnum3 = 3 + (parseInt(lib.config.custom_button_control_top) || 0); - var cbnum4 = 3 + (parseInt(lib.config.custom_button_control_bottom) || 0); - var cbnum5 = 2; - var cbnum6 = 2; - if (cbnum3 < 0) { - cbnum5 += cbnum3; - cbnum3 = 0; - } - if (cbnum4 < 0) { - cbnum6 += cbnum4; - cbnum4 = 0; - } - ui.css.buttonsheet = lib.init.sheet( - '#system>div>div, .caption>div>.tdnode{padding-top:' + cbnum1 + 'px !important;padding-bottom:' + cbnum2 + 'px !important}', - '#control>.control>div{padding-top:' + cbnum3 + 'px;padding-bottom:' + cbnum4 + 'px}', - '#control>.control{padding-top:' + cbnum5 + 'px;padding-bottom:' + cbnum6 + 'px}' - ); - } - } - }, - custom_button_system_top: { - name: '菜单上部高度', - init: '0x', - item: { - '-5x': '-5px', - '-4x': '-4px', - '-3x': '-3px', - '-2x': '-2px', - '-1x': '-1px', - '0x': '默认', - '1x': '1px', - '2x': '2px', - '3x': '3px', - '4x': '4px', - '5x': '5px', - }, - unfrequent: true, - onclick: function (item) { - game.saveConfig('custom_button_system_top', item); - lib.configMenu.appearence.config.custom_button.onclick('skip'); - } - }, - custom_button_system_bottom: { - name: '菜单下部高度', - init: '0x', - item: { - '-5x': '-5px', - '-4x': '-4px', - '-3x': '-3px', - '-2x': '-2px', - '-1x': '-1px', - '0x': '默认', - '1x': '1px', - '2x': '2px', - '3x': '3px', - '4x': '4px', - '5x': '5px', - }, - unfrequent: true, - onclick: function (item) { - game.saveConfig('custom_button_system_bottom', item); - lib.configMenu.appearence.config.custom_button.onclick('skip'); - } - }, - custom_button_control_top: { - name: '技能上部高度', - init: '0x', - item: { - '-5x': '-5px', - '-4x': '-4px', - '-3x': '-3px', - '-2x': '-2px', - '-1x': '-1px', - '0x': '默认', - '1x': '1px', - '2x': '2px', - '3x': '3px', - '4x': '4px', - '5x': '5px', - }, - unfrequent: true, - onclick: function (item) { - game.saveConfig('custom_button_control_top', item); - lib.configMenu.appearence.config.custom_button.onclick('skip'); - } - }, - custom_button_control_bottom: { - name: '技能下部高度', - init: '0x', - item: { - '-5x': '-5px', - '-4x': '-4px', - '-3x': '-3px', - '-2x': '-2px', - '-1x': '-1px', - '0x': '默认', - '1x': '1px', - '2x': '2px', - '3x': '3px', - '4x': '4px', - '5x': '5px', - }, - unfrequent: true, - onclick: function (item) { - game.saveConfig('custom_button_control_bottom', item); - lib.configMenu.appearence.config.custom_button.onclick('skip'); - } - }, - radius_size: { - name: '圆角大小', - init: 'default', - item: { - off: '关闭', - reduce: '减小', - default: '默认', - increase: '增大', - }, - unfrequent: true, - onclick: function (item) { - game.saveConfig('radius_size', item); - ui.window.dataset.radius_size = item; - } - }, - glow_phase: { - name: '当前回合角色高亮', - unfrequent: true, - init: 'yellow', - intro: '设置当前回合角色的边框颜色', - item: { - none: '无', - yellow: '黄色', - green: '绿色', - purple: '紫色', - }, - onclick: function (bool) { - game.saveConfig('glow_phase', bool); - lib.init.cssstyles(); - } - }, - fold_card: { - name: '折叠手牌', - init: true, - unfrequent: true, - }, - fold_mode: { - name: '折叠模式菜单', - intro: '关闭后模式菜单中“更多”内的项目将直接展开', - init: true, - unfrequent: true, - }, - seperate_control: { - name: '分离选项条', - init: true, - unfrequent: true, - intro: '开启后玩家在进行选择时不同的选项将分开,而不是连在一起', - }, - blur_ui: { - name: '模糊效果', - intro: '在暂停或打开菜单时开启模糊效果', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('blur_ui', bool); - if (bool) { - ui.window.classList.add('blur_ui'); - } - else { - ui.window.classList.remove('blur_ui'); - } - } - }, - glass_ui: { - name: '玻璃主题', - intro: '为游戏主题打开玻璃效果(手机暂不支持)', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('glass_ui', bool); - if (bool) { - ui.window.classList.add('glass_ui'); - } - else { - ui.window.classList.remove('glass_ui'); - } - } - }, - damage_shake: { - name: '伤害抖动', - intro: '角色受到伤害时的抖动效果', - init: true, - unfrequent: true, - }, - button_press: { - name: '按钮效果', - intro: '选项条被按下时将有按下效果', - init: true, - unfrequent: true, - }, - jiu_effect: { - name: '喝酒效果', - init: true, - unfrequent: true, - }, - animation: { - name: '游戏特效', - intro: '开启后出现属性伤害、回复体力等情况时会显示动画', - init: false, - unfrequent: true, - }, - skill_animation_type: { - name: '技能特效', - intro: '开启后觉醒技、限定技将显示全屏文字', - init: 'default', - unfrequent: true, - item: { - default: '默认', - old: '旧版', - off: '关闭' - } - }, - die_move: { - name: '阵亡效果', - intro: '阵亡后武将的显示效果', - init: 'flip', - unfrequent: true, - item: { - off: '关闭', - move: '移动', - flip: '翻面', - } - }, - target_shake: { - name: '目标效果', - intro: '一名玩家成为卡牌或技能的目标时的显示效果', - init: 'off', - item: { - off: '关闭', - zoom: '缩放', - shake: '抖动', - }, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('target_shake', bool); - ui.arena.dataset.target_shake = bool; - } - }, - turned_style: { - name: '翻面文字', - intro: '角色被翻面时显示“翻面”', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('turned_style', bool); - if (bool) { - ui.arena.classList.remove('hide_turned'); - } - else { - ui.arena.classList.add('hide_turned'); - } - } - }, - link_style2: { - name: '横置样式', - intro: '设置角色被横置时的样式', - init: 'chain', - unfrequent: true, - item: { - chain: '铁索', - rotate: '横置', - mark: '标记' - }, - onclick: function (style) { - var list = []; - for (var i = 0; i < game.players.length; i++) { - if (game.players[i].isLinked()) { - list.push(game.players[i]); - } - } - game.saveConfig('link_style2', style); - for (var i = 0; i < list.length; i++) { - if (get.is.linked2(list[i])) { - list[i].classList.add('linked2'); - list[i].classList.remove('linked'); - } - else { - list[i].classList.add('linked'); - list[i].classList.remove('linked2'); - } - } - if (style == 'chain') { - ui.arena.classList.remove('nolink'); - } - else { - ui.arena.classList.add('nolink'); - } - ui.updatem(); - } - }, - cardshape: { - name: '手牌显示', - intro: '将手牌设置为正方形或长方形', - init: 'default', - unfrequent: true, - item: { - default: '默认', - oblong: '长方', - }, - onclick: function (item) { - var linked = false; - if (game.me && game.me.isLinked()) { - linked = true; - } - game.saveConfig('cardshape', item); - if (item == 'oblong' && (game.layout == 'long' || game.layout == 'mobile' || game.layout == 'long2' || game.layout == 'nova')) { - ui.arena.classList.add('oblongcard'); - ui.window.classList.add('oblongcard'); - } - else { - ui.arena.classList.remove('oblongcard'); - ui.window.classList.remove('oblongcard'); - } - if (linked) { - if (get.is.linked2(game.me)) { - game.me.classList.remove('linked'); - game.me.classList.add('linked2'); - } - else { - game.me.classList.add('linked'); - game.me.classList.remove('linked2'); - } - } - } - }, - cardtempname: { - name: '视为卡牌名称显示', - intro: '显示强制视为类卡牌(如武魂),包括拆顺对话框内的判定牌(国色)转换等名称的显示方式', - init: 'image', - unfrequent: true, - item: { - default: '纵向', - horizon: '横向', - image: '图片', - off: '禁用', - }, - onclick: function (item) { - game.saveConfig('cardtempname', item); - if (!game.me || !game.me.getCards) return; - var hs = game.me.getCards('h'); - for (var i = 0; i < hs.length; i++) { - if (hs[i]._tempName) { - switch (item) { - case 'default': - case 'horizon': - case 'image': - ui.create.cardTempName(hs[i]); - break; - default: - hs[i]._tempName.delete(); - delete hs[i]._tempName; - } - } - } - } - }, - /*textequip:{ - name:'装备显示', - init:'image', - unfrequent:true, - item:{ - image:'图片', - text:'文字', - }, - onclick:function(item){ - game.saveConfig('textequip',item); - if(item=='text'&&(game.layout=='long'||game.layout=='mobile')){ - ui.arena.classList.add('textequip'); - } - else{ - ui.arena.classList.remove('textequip'); - } - } - },*/ - buttoncharacter_style: { - name: '选将样式', - init: 'default', - item: { - default: '默认', - simple: '精简', - old: '旧版' - }, - unfrequent: true, - }, - buttoncharacter_prefix: { - name: '武将前缀', - init: 'default', - item: { - default: '默认', - simple: '不显示颜色', - off: '不显示前缀' - }, - unfrequent: true, - }, - cursor_style: { - name: '鼠标指针', - init: 'auto', - intro: '设置为固定后鼠标指针将不随移动到的区域而变化', - unfrequent: true, - item: { - auto: '自动', - pointer: '固定' - }, - onclick: function (item) { - game.saveConfig('cursor_style', item); - if (item == 'pointer') { - ui.window.classList.add('nopointer'); - } - else { - ui.window.classList.remove('nopointer'); - } - } - }, - name_font: { - name: '人名字体', - init: 'xingkai', - unfrequent: true, - item: {}, - textMenu: function (node, link) { - if (link != 'default') { - node.style.fontFamily = link; - } - node.style.fontSize = '20px'; - }, - onclick: function (font) { - game.saveConfig('name_font', font); - lib.init.cssstyles(); - } - }, - identity_font: { - name: '身份字体', - init: 'huangcao', - unfrequent: true, - item: {}, - textMenu: function (node, link) { - if (link != 'default') { - node.style.fontFamily = link; - } - node.style.fontSize = '20px'; - }, - onclick: function (font) { - game.saveConfig('identity_font', font); - lib.init.cssstyles(); - } - }, - cardtext_font: { - name: '卡牌字体', - init: 'default', - unfrequent: true, - item: {}, - textMenu: function (node, link) { - if (link != 'default') { - node.style.fontFamily = link; - } - node.style.fontSize = '20px'; - }, - onclick: function (font) { - game.saveConfig('cardtext_font', font); - lib.init.cssstyles(); - } - }, - global_font: { - name: '界面字体', - init: 'default', - unfrequent: true, - item: {}, - textMenu: function (node, link) { - if (link != 'default') { - node.style.fontFamily = link; - } - else { - node.style.fontFamily = "'STHeiti','SimHei','Microsoft JhengHei','Microsoft YaHei','WenQuanYi Micro Hei','Suits',Helvetica,Arial,sans-serif"; - } - node.style.fontSize = '20px'; - }, - onclick: function (font) { - game.saveConfig('global_font', font); - lib.init.cssstyles(); - } - }, - suits_font: { - name: '替换花色字体', - init: true, - unfrequent: true, - intro: '使用全角字符的花色替代系统自带的花色(重启游戏后生效)', - onclick: function (bool) { - game.saveConfig('suits_font', bool); - } - }, - update: function (config, map) { - if (lib.config.custom_button) { - map.custom_button_system_top.show(); - map.custom_button_system_bottom.show(); - map.custom_button_control_top.show(); - map.custom_button_control_bottom.show(); - } - else { - map.custom_button_system_top.hide(); - map.custom_button_system_bottom.hide(); - map.custom_button_control_top.hide(); - map.custom_button_control_bottom.hide(); - } - if (lib.config.change_skin) { - map.change_skin_auto.show(); - } - else { - map.change_skin_auto.hide(); - } - if (lib.config.image_background_random) { - map.image_background_blur.show(); - map.image_background.hide(); - // map.import_background.hide(); - } - else { - map.image_background.show(); - if (lib.config.image_background == 'default') { - map.image_background_blur.hide(); - } - else { - map.image_background_blur.show(); - } - // if(lib.config.image_background=='custom'&&lib.db){ - // map.import_background.show(); - // } - // else{ - // map.import_background.hide(); - // } - } - if (lib.config.layout == 'long' || lib.config.layout == 'mobile') { - //map.textequip.show(); - map.cardshape.show(); - map.phonelayout.show(); - } - else { - //map.textequip.hide(); - if (lib.config.layout == 'long2' || lib.config.layout == 'nova') { - map.phonelayout.show(); - map.cardshape.show(); - } - else { - map.phonelayout.hide(); - map.cardshape.hide(); - } - } - if (lib.config.layout == 'long') { - // map.fewplayer.show(); - map.player_height.show(); - } - else { - // map.fewplayer.hide(); - if (lib.config.layout == 'long2') { - map.player_height.show(); - } - else { - map.player_height.hide(); - } - } - if (lib.config.layout == 'nova') { - map.player_height_nova.show(); - } - else { - map.player_height_nova.hide(); - } - if (lib.config.touchscreen) { - map.cursor_style.hide(); - } - else { - map.cursor_style.show(); - } - if (lib.config.border_style == 'auto') { - map.autoborder_count.show(); - map.autoborder_start.show(); - } - else { - map.autoborder_count.hide(); - map.autoborder_start.hide(); - } - }, - } - }, - view: { - name: '显示', - config: { - update: function (config, map) { - if (lib.config.mode == 'versus' || lib.config.mode == 'chess' || lib.config.mode == 'tafang' || lib.config.mode == 'boss') { - map.show_handcardbutton.show(); - } - else { - map.show_handcardbutton.hide(); - } - if (lib.config.touchscreen) { - map.pop_logv.hide(); - } - else { - map.pop_logv.show(); - } - if (lib.device) { - if (lib.device == 'android') { - map.show_statusbar_android.show(); - map.show_statusbar_ios.hide(); - } - else if (lib.device == 'ios') { - map.show_statusbar_ios.show(); - map.show_statusbar_android.hide(); - } - if (!game.download) { - setTimeout(function () { - if (!window.StatusBar) { - map.show_statusbar.hide(); - } - }, 5000); - } - } - else { - map.show_statusbar_ios.hide(); - map.show_statusbar_android.hide(); - } - if (get.is.phoneLayout()) { - map.remember_round_button.show(); - map.popequip.show(); - map.filternode_button.show(); - map.show_pause.hide(); - map.show_auto.hide(); - map.show_replay.hide(); - map.show_round_menu.show(); - } - else { - map.show_pause.show(); - map.show_auto.show(); - map.show_replay.show(); - map.show_round_menu.hide(); - map.remember_round_button.hide(); - map.popequip.hide(); - map.filternode_button.hide(); - } - if (lib.config.show_card_prompt) { - map.hide_card_prompt_basic.show(); - map.hide_card_prompt_equip.show(); - } - else { - map.hide_card_prompt_basic.hide(); - map.hide_card_prompt_equip.hide(); - } - if (lib.config.show_log != 'off') { - map.clear_log.show(); - } - else { - map.clear_log.hide(); - } - if (get.is.phoneLayout()) { - map.show_time2.show(); - map.show_time.hide(); - if (lib.config.show_time2) { - map.watchface.show(); - } - else { - map.watchface.hide(); - } - } - else { - map.show_time2.hide(); - map.show_time.show(); - map.watchface.hide(); - } - if (lib.config.show_extensionmaker) { - map.show_extensionshare.show(); - } - else { - map.show_extensionshare.hide(); - } - }, - show_history: { - name: '出牌记录栏', - init: 'off', - intro: '在屏幕左侧或右侧显示出牌记录', - unfrequent: true, - item: { - off: '关闭', - left: '靠左', - right: '靠右', - }, - onclick: function (bool) { - if (lib.config.show_history == 'right') ui.window.addTempClass('rightbar2'); - game.saveConfig('show_history', bool); - if (_status.video || !_status.prepareArena) return; - if (bool == 'left') { - ui.window.classList.add('leftbar'); - ui.window.classList.remove('rightbar'); - } - else if (bool == 'right') { - ui.window.classList.remove('leftbar'); - ui.window.classList.add('rightbar'); - } - else { - ui.window.classList.remove('leftbar'); - ui.window.classList.remove('rightbar'); - } - } - }, - pop_logv: { - name: '自动弹出记录', - init: false, - unfrequent: true - }, - show_log: { - name: '历史记录栏', - init: 'off', - intro: '在屏幕中部显示出牌文字记录', - unfrequent: true, - item: { - off: '关闭', - left: '靠左', - center: '居中', - right: '靠右', - }, - onclick: function (bool) { - game.saveConfig('show_log', bool); - if (lib.config.show_log != 'off') { - ui.arenalog.style.display = ''; - ui.arenalog.dataset.position = bool; - } - else { - ui.arenalog.style.display = 'none'; - ui.arenalog.innerHTML = ''; - } - } - }, - clear_log: { - name: '自动清除历史记录', - init: false, - unfrequent: true, - intro: '开启后将定时清除历史记录栏的条目(而不是等记录栏满后再清除)' - }, - log_highlight: { - name: '历史记录高亮', - init: true, - unfrequent: true, - intro: '开启后历史记录不同类别的信息将以不同颜色显示', - }, - show_time: { - name: '显示时间', - intro: '在屏幕顶部显示当前时间', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_time', bool); - if (bool) { - ui.time.style.display = ''; - } - else { - ui.time.style.display = 'none'; - } - } - }, - show_time2: { - name: '显示时间', - intro: '在触屏按钮处显示当前时间', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_time2', bool); - if (bool) { - ui.roundmenu.classList.add('clock'); - } - else { - ui.roundmenu.classList.remove('clock'); - } - } - }, - watchface: { - name: '表盘样式', - init: 'none', - unfrequent: true, - item: { - none: '默认', - simple: '简约', - }, - onclick: function (item) { - game.saveConfig('watchface', item); - ui.roundmenu.dataset.watchface = item; - } - }, - show_time3: { - name: '显示游戏时间', - init: false, - unfrequent: true - }, - show_statusbar_android: { - name: '显示状态栏', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_statusbar', bool); - if (window.StatusBar && lib.device == 'android') { - if (bool) { - window.StatusBar.overlaysWebView(false); - window.StatusBar.backgroundColorByName('black'); - window.StatusBar.show(); - } - else { - window.StatusBar.hide(); - } - } - } - }, - show_statusbar_ios: { - name: '显示状态栏', - init: 'off', - unfrequent: true, - item: { - default: '默认', - overlay: '嵌入', - auto: '自动', - off: '关闭' - }, - onclick: function (bool) { - game.saveConfig('show_statusbar_ios', bool); - if (window.StatusBar && lib.device == 'ios') { - if (bool != 'off' && bool != 'auto') { - if (lib.config.show_statusbar_ios == 'default') { - window.StatusBar.overlaysWebView(false); - document.body.classList.remove('statusbar'); - } - else { - window.StatusBar.overlaysWebView(true); - document.body.classList.add('statusbar'); - } - window.StatusBar.backgroundColorByName('black'); - window.StatusBar.show(); - } - else { - document.body.classList.remove('statusbar'); - window.StatusBar.hide(); - } - } - } - }, - show_card_prompt: { - name: '显示出牌信息', - intro: '出牌时在使用者上显示卡牌名称', - init: true, - unfrequent: true, - }, - hide_card_prompt_basic: { - name: '隐藏基本牌信息', - intro: '不显示基本牌名称', - init: false, - unfrequent: true, - }, - hide_card_prompt_equip: { - name: '隐藏装备牌信息', - intro: '不显示装备牌名称', - init: false, - unfrequent: true, - }, - show_phase_prompt: { - name: '显示阶段信息', - intro: '在当前回合不同阶段开始时显示阶段名称', - init: true, - unfrequent: true, - }, - show_phaseuse_prompt: { - name: '出牌阶段提示', - intro: '在你出牌时显示提示文字', - init: true, - unfrequent: true, - }, - auto_popped_config: { - name: '自动弹出选项', - intro: '鼠标移至选项按钮时弹出模式选择菜单', - init: true, - unfrequent: true, - }, - auto_popped_history: { - name: '自动弹出历史', - intro: '鼠标移至暂停按钮时弹出历史记录菜单', - init: false, - unfrequent: true, - }, - show_round_menu: { - name: '显示触屏按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - if (get.is.nomenu('show_round_menu', bool)) return false; - game.saveConfig('show_round_menu', bool); - if (bool && ui.roundmenu) { - ui.roundmenu.style.display = ''; - } - else { - ui.roundmenu.style.display = 'none'; - alert('关闭触屏按钮后可通过手势打开菜单(默认为下划)'); - } - } - }, - remember_round_button: { - name: '记住按钮位置', - intro: '重新开始后触屏按钮将保存的上一局的位置', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('remember_round_button', bool); - if (!bool) { - ui.click.resetround(); - } - } - }, - remember_dialog: { - name: '记住对话框位置', - intro: '移动对话框后新的对话框也将在移动后的位置显示', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('remember_dialog', bool); - if (!bool) { - if (ui.dialog) { - var dialog = ui.dialog; - dialog.style.transform = ''; - dialog._dragtransform = [0, 0]; - dialog.style.transition = 'all 0.3s'; - dialog._dragtouches; - dialog._dragorigin; - dialog._dragorigintransform; - setTimeout(function () { - dialog.style.transition = ''; - }, 500); - } - game.saveConfig('dialog_transform', [0, 0]); - } - } - }, - transparent_dialog: { - name: '堆叠对话框虚化', - init: false, - intro: '当具有static属性的对话框堆叠(如五谷丰登对话框中提示无懈可击)时,将后方的对话框变为半透明', - onclick: function (bool) { - game.saveConfig('transparent_dialog', bool); - if (bool) { - for (var i = 0; i < ui.dialogs.length; i++) { - if (ui.dialogs[i] != ui.dialog && ui.dialogs[i].static) { - ui.dialogs[i].unfocus(); - } - } - } - else { - for (var i = 0; i < ui.dialogs.length; i++) { - if (ui.dialogs[i] != ui.dialog && ui.dialogs[i].static) { - ui.dialogs[i].refocus(); - } - } - } - } - }, - show_rarity: { - name: '显示武将评级', - init: false, - intro: '仅供娱乐,重启后生效', - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_rarity', bool); - } - }, - mark_identity_style: { - name: '标记身份操作', - intro: '设置单击身份按钮时的操作', - unfrequent: true, - init: 'menu', - item: { - menu: '菜单', - click: '单击', - }, - }, - character_dialog_tool: { - name: '自由选将显示', - intro: '点击自由选将时默认显示的条目', - init: '最近', - item: { - '收藏': '收藏', - '最近': '最近', - 'all': '全部' - }, - unfrequent: true, - }, - recent_character_number: { - name: '最近使用武将', - intro: '自由选将对话框中最近使用武将的数量', - init: '12', - item: { - '6': '6', - '12': '12', - '20': '24', - '30': '36', - }, - unfrequent: true - }, - popequip: { - name: '触屏装备选择', - intro: '设置触屏布局中选择装备的方式', - init: true, - unfrequent: true, - }, - filternode_button: { - name: '触屏筛选按钮', - intro: '设置自由选将对话框中筛选按钮的样式', - init: true, - unfrequent: true, - }, - show_charactercard: { - name: '显示武将资料', - intro: '在武将界面单击时弹出武将资料卡', - init: true, - unfrequent: true - }, - show_favourite: { - name: '显示添加收藏', - intro: '在角色的右键菜单中显示添加收藏', - init: false, - unfrequent: true - }, - show_favmode: { - name: '显示模式收藏', - intro: '快捷菜单中显示收藏模式', - init: true, - unfrequent: true - }, - show_favourite_menu: { - name: '显示收藏菜单', - intro: '在选项-武将中显示收藏一栏', - init: true, - unfrequent: true - }, - show_ban_menu: { - name: '显示禁将菜单', - intro: '在选项-武将中显示禁将一栏', - init: true, - unfrequent: true - }, - right_range: { - name: '显示距离信息', - intro: '在角色的右键菜单中显示距离等信息', - init: true, - unfrequent: true - }, - hide_card_image: { - name: '隐藏卡牌背景', - intro: '所有卡牌将使用文字作为背景', - init: false, - unfrequent: true, - restart: true, - }, - show_name: { - name: '显示角色名称', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_name', bool); - if (bool) { - ui.arena.classList.remove('hide_name'); - } - else { - ui.arena.classList.add('hide_name'); - } - } - }, - show_sex: { - name: '显示角色性别', - intro: '在角色的右键菜单中显示角色性别', - init: true, - unfrequent: true - }, - show_group: { - name: '显示角色势力', - intro: '在角色的右键菜单中显示角色势力', - init: true, - unfrequent: true - }, - show_replay: { - name: '显示重来按钮', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_replay', bool); - if (lib.config.show_replay) { - ui.replay.style.display = ''; - } - else { - ui.replay.style.display = 'none'; - } - } - }, - show_playerids: { - name: '显示身份按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_playerids', bool); - if (lib.config.show_playerids) { - ui.playerids.style.display = ''; - } - else { - ui.playerids.style.display = 'none'; - } - } - }, - show_sortcard: { - name: '显示整理手牌按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_sortcard', bool); - if (lib.config.show_sortcard) { - ui.sortCard.style.display = ''; - } - else { - ui.sortCard.style.display = 'none'; - } - } - }, - show_pause: { - name: '显示暂停按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_pause', bool); - if (lib.config.show_pause) { - ui.pause.style.display = ''; - } - else { - ui.pause.style.display = 'none'; - } - } - }, - show_auto: { - name: '显示托管按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_auto', bool); - if (lib.config.show_auto) { - ui.auto.style.display = ''; - } - else { - ui.auto.style.display = 'none'; - } - } - }, - show_volumn: { - name: '显示音量按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_volumn', bool); - if (lib.config.show_volumn) { - ui.volumn.style.display = ''; - } - else { - ui.volumn.style.display = 'none'; - } - } - }, - show_cardpile: { - name: '显示牌堆按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_cardpile', bool); - if (bool) { - ui.cardPileButton.style.display = ''; - } - else { - ui.cardPileButton.style.display = 'none'; - } - } - }, - show_cardpile_number: { - name: '显示剩余牌数', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_cardpile_number', bool); - if (bool) { - ui.cardPileNumber.style.display = ''; - } - else { - ui.cardPileNumber.style.display = 'none'; - } - } - }, - show_handcardbutton: { - name: '显示手牌按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_handcardbutton', bool); - } - }, - show_giveup: { - name: '显示投降按钮', - init: true, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_giveup', bool); - } - }, - show_wuxie: { - name: '显示无懈按钮', - intro: '在右上角显示不询问无懈', - init: false, - unfrequent: true, - onclick: function (bool) { - game.saveConfig('show_wuxie', bool); - if (lib.config.show_wuxie) { - ui.wuxie.style.display = ''; - } - else { - ui.wuxie.style.display = 'none'; - } - } - }, - wuxie_right: { - name: '无懈按钮靠左', - init: true, - unfrequent: true, - }, - show_discardpile: { - name: '暂停时显示弃牌堆', - init: false, - unfrequent: true, - }, - show_extensionmaker: { - name: '显示制作扩展', - init: true, - unfrequent: true, - }, - show_extensionshare: { - name: '显示分享扩展', - init: true, - unfrequent: true, - }, - show_characternamepinyin: { - name: '显示武将名注解', - intro: '在武将资料卡显示武将名及其注解、性别、势力、体力等信息', - init: 'showPinyin', - unfrequent: true, - item: { - doNotShow: '不显示', - showPinyin: '拼音(样式一)', - showCodeIdentifier: '代码ID(样式一)', - showPinyin2: '拼音(样式二)', - showCodeIdentifier2: '代码ID(样式二)', - }, - visualMenu: (node, link, name) => { - node.classList.add('button', 'character'); - const style = node.style; - style.alignItems = 'center'; - style.animation = 'background-position-left-center-right-center-left-center 15s ease infinite'; - style.background = 'linear-gradient(-45deg, #EE7752, #E73C7E, #23A6D5, #23D5AB)'; - style.backgroundSize = '400% 400%'; - style.display = 'flex'; - style.height = '60px'; - style.justifyContent = 'center'; - style.width = '180px'; - const firstChild = node.firstChild; - firstChild.removeAttribute('class'); - firstChild.style.position = 'initial'; - if (link == 'doNotShow') return; - const ruby = document.createElement('ruby'); - ruby.textContent = name; - const rt = document.createElement('rt'); - rt.style.fontSize = 'smaller'; - if (link == 'showPinyin2' || link == 'showCodeIdentifier2') { - rt.textContent = link == 'showCodeIdentifier2' ? '[' + link + ']' : '[' + get.pinyin(name) + ']'; - ruby.appendChild(rt); - } else { - const leftParenthesisRP = document.createElement('rp'); - leftParenthesisRP.textContent = '('; - ruby.appendChild(leftParenthesisRP); - rt.textContent = link == 'showCodeIdentifier' ? link : get.pinyin(name).join(' '); - ruby.appendChild(rt); - const rightParenthesisRP = document.createElement('rp'); - rightParenthesisRP.textContent = ')'; - ruby.appendChild(rightParenthesisRP); - } - firstChild.innerHTML = ruby.outerHTML; - } - }, - show_skillnamepinyin: { - name: '显示技能名注解', - intro: '在武将资料卡显示技能名注解', - get init() { - return lib.configMenu.view.config.show_characternamepinyin.init; - }, - set init(newVal) { - lib.configMenu.view.config.show_characternamepinyin.init = newVal; - }, - get unfrequent() { - return lib.configMenu.view.config.show_characternamepinyin.unfrequent; - }, - set unfrequent(newVal) { - lib.configMenu.view.config.show_characternamepinyin.unfrequent = newVal; - }, - get item() { - return lib.configMenu.view.config.show_characternamepinyin.item; - }, - set item(newVal) { - lib.configMenu.view.config.show_characternamepinyin.item = newVal; - }, - get visualMenu() { - return lib.configMenu.view.config.show_characternamepinyin.visualMenu; - }, - set visualMenu(newVal) { - lib.configMenu.view.config.show_characternamepinyin.visualMenu = newVal; - }, - } - } - }, - audio: { - name: '音效', - config: { - update: function (config, map) { - if (lib.config.background_music == 'music_custom' && (lib.device || lib.node)) { - map.import_music.show(); - } - else { - map.import_music.hide(); - } - map.clear_background_music[get.is.object(lib.config.customBackgroundMusic) ? 'show' : 'hide'](); - ui.background_music_setting = map.background_music; - map.background_music._link.config.updatex.call(map.background_music, []); - }, - background_music: { - updatex: function () { - this.lastChild.innerHTML = this._link.config.item[lib.config.background_music]; - var menu = this._link.menu; - for (var i = 0; i < menu.childElementCount; i++) { - if (!['music_off', 'music_custom', 'music_random'].concat(lib.config.all.background_music).includes(menu.childNodes[i]._link)) menu.childNodes[i].delete(); - } - }, - name: '背景音乐', - init: true, - item: { - music_default: '默认', - }, - onclick: function (item) { - game.saveConfig('background_music', item); - game.playBackgroundMusic(); - } - }, - import_music: { - name: '
    ' + - '' + - '
    ', - clear: true, - }, - background_audio: { - name: '游戏音效', - init: true, - }, - background_speak: { - name: '人物配音', - init: true, - }, - equip_audio: { - name: '装备配音', - init: false, - }, - repeat_audio: { - name: '播放重复语音', - init: false, - }, - volumn_audio: { - name: '音效音量', - init: 8, - item: { - '0': '〇', - '1': '一', - '2': '二', - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '7': '七', - '8': '八', - }, - onclick: function (volume) { - game.saveConfig('volumn_audio', parseInt(volume)); - } - }, - volumn_background: { - name: '音乐音量', - init: 8, - item: { - '0': '〇', - '1': '一', - '2': '二', - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '7': '七', - '8': '八', - }, - onclick: function (volume) { - game.saveConfig('volumn_background', parseInt(volume)); - ui.backgroundMusic.volume = volume / 8; - } - }, - clear_background_music: { - name: '清除自定义背景音乐', - clear: true, - onclick: function () { - if (confirm('是否清除已导入的所有自定义背景音乐?(该操作不可撤销!)')) { - for (var i in lib.config.customBackgroundMusic) { - lib.config.all.background_music.remove(i); - if (i.startsWith('cdv_')) { - game.removeFile('audio/background/' + i + '.mp3'); - } - else { - game.deleteDB('audio', i); - } - } - lib.config.customBackgroundMusic = null; - game.saveConfig('customBackgroundMusic', null); - game.saveConfig('background_music', 'music_off'); - if (!_status._aozhan) game.playBackgroundMusic(); - } - }, - }, - } - }, - skill: { - name: '技能', - config: { - update: function (config, map) { - for (var i in map) { - if (map[i]._link.config.type == 'autoskill') { - if (!lib.config.autoskilllist.includes(i)) { - map[i].classList.add('on'); - } - else { - map[i].classList.remove('on'); - } - } - else if (map[i]._link.config.type == 'banskill') { - if (!lib.config.forbidlist.includes(i)) { - map[i].classList.add('on'); - } - else { - map[i].classList.remove('on'); - } - } - } - } - } - }, - others: { - name: '其它', - config: { - // reset_database:{ - // name:'重置游戏', - // onclick:function(){ - // var node=this; - // if(node._clearing){ - // if(indexedDB) indexedDB.deleteDatabase(lib.configprefix+'data'); - // game.reload(); - // return; - // } - // node._clearing=true; - // node.innerHTML='单击以确认 (3)'; - // setTimeout(function(){ - // node.innerHTML='单击以确认 (2)'; - // setTimeout(function(){ - // node.innerHTML='单击以确认 (1)'; - // setTimeout(function(){ - // node.innerHTML='重置游戏录像'; - // delete node._clearing; - // },1000); - // },1000); - // },1000); - // }, - // clear:true - // }, - reset_game: { - name: '重置游戏设置', - onclick: function () { - var node = this; - if (node._clearing) { - var noname_inited = localStorage.getItem('noname_inited'); - var onlineKey = localStorage.getItem(lib.configprefix + 'key'); - localStorage.clear(); - if (noname_inited) { - localStorage.setItem('noname_inited', noname_inited); - } - if (onlineKey) { - localStorage.setItem(lib.configprefix + 'key', onlineKey); - } - game.deleteDB('config'); - game.deleteDB('data'); - game.reload(); - return; - } - node._clearing = true; - node.firstChild.innerHTML = '单击以确认 (3)'; - setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (2)'; - setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (1)'; - setTimeout(function () { - node.firstChild.innerHTML = '重置游戏设置'; - delete node._clearing; - }, 1000); - }, 1000); - }, 1000); - }, - clear: true - }, - reset_hiddenpack: { - name: '重置隐藏内容', - onclick: function () { - if (this.firstChild.innerHTML != '已重置') { - this.firstChild.innerHTML = '已重置'; - game.saveConfig('hiddenModePack', []); - game.saveConfig('hiddenCharacterPack', []); - game.saveConfig('hiddenCardPack', []); - game.saveConfig('hiddenPlayPack', []); - game.saveConfig('hiddenBackgroundPack', []); - var that = this; - setTimeout(function () { - that.firstChild.innerHTML = '重置隐藏内容'; - setTimeout(function () { - if (confirm('是否重新启动使改变生效?')) { - game.reload(); - } - }); - }, 500); - } - }, - clear: true - }, - reset_tutorial: { - name: '重置新手向导', - onclick: function () { - if (this.firstChild.innerHTML != '已重置') { - this.firstChild.innerHTML = '已重置'; - game.saveConfig('new_tutorial', false); - game.saveConfig('prompt_hidebg'); - game.saveConfig('prompt_hidepack'); - var that = this; - setTimeout(function () { - that.firstChild.innerHTML = '重置新手向导'; - }, 500); - } - }, - clear: true - }, - import_data: { - name: '导入游戏设置', - onclick: function () { - ui.import_data_button.classList.toggle('hidden'); - }, - clear: true - }, - import_data_button: { - name: '
    ' + - '' + - '
    ', - clear: true, - }, - export_data: { - name: '导出游戏设置', - onclick: function () { - var data; - var export_data = function (data) { - game.export(lib.init.encode(JSON.stringify(data)), '无名杀 - 数据 - ' + (new Date()).toLocaleString()); - }; - if (!lib.db) { - data = {}; - for (var i in localStorage) { - if (i.startsWith(lib.configprefix)) { - data[i] = localStorage[i]; - } - } - export_data(data); - } - else { - game.getDB('config', null, function (data1) { - game.getDB('data', null, function (data2) { - export_data({ - config: data1, - data: data2 - }); - }); - }); - } - - }, - clear: true - }, - redownload_game: { - name: '重新下载游戏', - onclick: function () { - var node = this; - if (node._clearing) { - localStorage.removeItem('noname_inited'); - game.reload(); - return; - } - node._clearing = true; - node.firstChild.innerHTML = '单击以确认 (3)'; - setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (2)'; - setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (1)'; - setTimeout(function () { - node.firstChild.innerHTML = '重新下载游戏'; - delete node._clearing; - }, 1000); - }, 1000); - }, 1000); - }, - clear: true - }, - update: function (config, map) { - if (lib.device || lib.node) { - map.redownload_game.show(); - } - else { - map.redownload_game.hide(); - } - } - // trim_game:{ - // name:'隐藏非官方扩展包', - // onclick:function(){ - // if(this.innerHTML!='已隐藏'){ - // this.innerHTML='已隐藏'; - // var pack=lib.config.all.cards.slice(0); - // if(Array.isArray(lib.config.hiddenCardPack)){ - // for(var i=0;i game.players.length * num && game.showIdentity) { - _status.identityShown = true; - game.showIdentity(false); - } - }, - intro: '游戏进行若干轮将自动显示所有角色的身份', - }, - auto_mark_identity: { - name: '自动标记身份', - init: true, - intro: '根据角色的出牌行为自动标记可能的身份', - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - enhance_zhu: { - name: '加强主公', - init: false, - restart: true, - intro: '为主公增加一个额外技能' - }, - free_choose: { - name: '自由选将', - init: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - } - }, - change_identity: { - name: '自由选择身份和座位', - init: true, - onclick: function (bool) { - game.saveConfig('change_identity', bool, this._link.config.mode); - if (get.mode() != 'identity' || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - var dialog; - if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; - else dialog = _status.event.dialog; - if (!_status.brawl || !_status.brawl.noAddSetting) { - if (!dialog.querySelector('table') && get.config('change_identity')) _status.event.getParent().addSetting(dialog); - else _status.event.getParent().removeSetting(dialog); - } - ui.update(); - } - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (get.mode() != 'identity' || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - } - }, - change_card: { - name: '开启手气卡', - init: 'disabled', - item: { - disabled: '禁用', - once: '一次', - twice: '两次', - unlimited: '无限', - }, - }, - round_one_use_fury: { - name: '开启首轮强化卡牌', - init: false, - frequent: false, - restart: true, - intro: '谋攻篇规则为第二轮开始才可使用怒气强化卡牌,开启此选项从游戏开始即可强化卡牌。' - }, - nei_auto_mark_camouflage: { - name: '内奸自动标记伪装反贼', - intro: '玩家内奸在游戏开始洞察结束后,自动将被洞察角色标记为反贼。', - init: false, - unfrequent: true, - }, - continue_game: { - name: '显示再战', - init: false, - onclick: function (bool) { - game.saveConfig('continue_game', bool, this._link.config.mode); - if (get.config('continue_game') && get.mode() == 'identity') { - if (!ui.continue_game && _status.over && !_status.brawl && !game.no_continue_game) { - ui.continue_game = ui.create.control('再战', game.reloadCurrent); - } - } - else if (ui.continue_game) { - ui.continue_game.close(); - delete ui.continue_game; - } - }, - intro: '游戏结束后可选择用相同的武将再进行一局游戏' - }, - dierestart: { - name: '死亡后显示重来', - init: true, - onclick: function (bool) { - game.saveConfig('dierestart', bool, this._link.config.mode); - if (get.config('dierestart') && get.mode() == 'identity') { - if (!ui.restart && game.me.isDead() && !_status.connectMode) { - ui.restart = ui.create.control('restart', game.reload); - } - } - else if (ui.restart) { - ui.restart.close(); - delete ui.restart; - } - } - }, - revive: { - name: '死亡后显示复活', - init: false, - onclick: function (bool) { - game.saveConfig('revive', bool, this._link.config.mode); - if (get.config('revive') && get.mode() == 'identity') { - if (!ui.revive && game.me.isDead()) { - ui.revive = ui.create.control('revive', ui.click.dierevive); - } - } - else if (ui.revive) { - ui.revive.close(); - delete ui.revive; - } - } - }, - ban_identity: { - name: '屏蔽身份', - init: 'off', - item: { - off: '关闭', - zhu: '主公', - zhong: '忠臣', - nei: '内奸', - fan: '反贼', - }, - }, - ban_identity2: { - name: '屏蔽身份2', - init: 'off', - item: { - off: '关闭', - zhu: '主公', - zhong: '忠臣', - nei: '内奸', - fan: '反贼', - }, - }, - ban_identity3: { - name: '屏蔽身份3', - init: 'off', - item: { - off: '关闭', - zhu: '主公', - zhong: '忠臣', - nei: '内奸', - fan: '反贼', - }, - }, - ai_strategy: { - name: '内奸策略', - init: 'ai_strategy_1', - item: { - ai_strategy_1: '均衡', - ai_strategy_2: '偏反', - ai_strategy_3: '偏忠', - ai_strategy_4: '酱油', - ai_strategy_5: '天使', - ai_strategy_6: '仇主', - }, - intro: '设置内奸对主忠反的态度' - }, - difficulty: { - name: 'AI对人类态度', - init: 'normal', - item: { - easy: '友好', - normal: '一般', - hard: '仇视', - }, - }, - choice_zhu: { - name: '主公候选武将数', - init: '3', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - limit_zhu: { - name: '常备主候选武将数', - init: 'group', - restart: true, - item: { - off: '不限制', - group: '按势力筛选', - '4': '四', - '6': '六', - '8': '八', - }, - }, - choice_zhong: { - name: '忠臣候选武将数', - init: '4', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - choice_nei: { - name: '内奸候选武将数', - init: '5', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - choice_fan: { - name: '反贼候选武将数', - init: '3', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - enable_commoner: { - name: '启用平民', - init: false, - restart: true, - frequent: false, - intro: '开启后游戏中将有一个平民(身份)加入游戏。
    具体规则请查看帮助。', - }, - choice_commoner: { - name: '平民候选武将数', - init: '4', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - enable_year_limit: { - name: '启用年机制', - init: false, - restart: true, - frequent: false, - intro: '开启后将会加入年机制。
    年机制的具体规则请查看帮助。', - }, - } - }, - guozhan: { - name: '国战', - connect: { - connect_guozhan_mode: { - name: '游戏模式', - init: 'normal', - item: { - normal: '势备', - yingbian: '应变', - old: '怀旧', - }, - frequent: true, - restart: true, - intro: '
  • 势备:默认模式,使用线下《君临天下·势备篇》的牌堆进行游戏。
  • 应变:使用OL的应变国战牌堆进行游戏。
  • 怀旧:使用传统国战的牌堆进行游戏。', - }, - connect_player_number: { - name: '游戏人数', - init: '8', - get item() { - return lib.mode.guozhan.config.player_number.item; - }, - frequent: true, - restart: true, - }, - connect_aozhan: { - name: '鏖战模式', - init: true, - intro: '若开启此选项,则将在游戏中引入“鏖战模式”的规则:
    当游戏中仅剩四名或更少角色时(七人以下游戏时改为三名或更少),若此时全场没有超过一名势力相同的角色,则从一个新的回合开始,游戏进入鏖战模式直至游戏结束。
    ◇在鏖战模式下,【桃】只能当做【杀】或【闪】使用或打出,不能用来回复体力。
    注:进入鏖战模式后,即使之后有两名或者更多势力相同的角色出现,仍然不会取消鏖战模式。', - frequent: true, - restart: true, - }, - get connect_separatism() { - return lib.mode.guozhan.config.separatism; - }, - connect_initshow_draw: { - name: '首亮奖励', - item: { - 'off': '关闭', - 'draw': '摸牌', - 'mark': '标记', - }, - init: 'mark', - frequent: true, - intro: '第一个明置武将牌的角色可获得首亮奖励' - }, - connect_viewnext: { - name: '观看下家副将', - init: false, - intro: '若开启此选项,所有的玩家将在挑选武将后,分发起始手牌之前,分别观看自己下家的副将。', - }, - connect_zhulian: { - name: '珠联璧合', - init: true, - // frequent:true, - intro: '主将和副将都明置后,若为特定组合,可获得【珠联璧合】标记' - }, - connect_junzhu: { - name: '替换君主', - init: true, - // frequent:true, - restart: true, - intro: '若开启此选项,玩家的第一个回合开始时,若其主武将牌有对应的君主武将牌,则其可以将此武将牌替换为对应的君主武将牌,然后重新调整体力上限。若玩家的体力上限因此增大,则玩家回复等量的体力。' - }, - connect_change_card: { - name: '启用手气卡', - init: false, - frequent: true, - restart: true, - }, - // connect_ban_weak:{ - // name:'屏蔽弱将', - // init:false, - // restart:true, - // }, - // connect_ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - }, - config: { - update: function (config, map) { - if (config.onlyguozhan) { - map.junzhu.show(); - } - else { - map.junzhu.hide(); - } - ui.aozhan_bgm = map.aozhan_bgm; - map.aozhan_bgm._link.config.updatex.call(map.aozhan_bgm, []); - }, - guozhan_mode: { - name: '游戏模式', - init: 'normal', - item: { - normal: '势备', - yingbian: '应变', - old: '怀旧', - free: '自由', - }, - frequent: true, - restart: true, - intro: '
  • 势备:默认模式,使用线下《君临天下·势备篇》的牌堆进行游戏。
  • 应变:使用OL的应变国战牌堆进行游戏。
  • 怀旧:使用传统国战的牌堆进行游戏。
  • 自由:使用玩家的自定义牌堆进行游戏。', - }, - player_number: { - name: '游戏人数', - init: '8', - get item() { - const minimumNumberOfPlayers = 2, maximumNumberOfPlayers = Math.max(_status.maximumNumberOfPlayers || 12, minimumNumberOfPlayers), item = {}; - for (let playerNumber = minimumNumberOfPlayers; playerNumber <= maximumNumberOfPlayers; playerNumber++) { - item[playerNumber] = `${get.cnNumber(playerNumber)}人`; - } - return item; - }, - frequent: true, - restart: true, - }, - aozhan: { - name: '鏖战模式', - init: true, - frequent: true, - restart: true, - intro: '若开启此选项,则将在游戏中引入“鏖战模式”的规则:
    当游戏中仅剩四名或更少角色时(七人以下游戏时改为三名或更少),若此时全场没有超过一名势力相同的角色,则从一个新的回合开始,游戏进入鏖战模式直至游戏结束。
    ◇在鏖战模式下,【桃】只能当做【杀】或【闪】使用或打出,不能用来回复体力。
    注:进入鏖战模式后,即使之后有两名或者更多势力相同的角色出现,仍然不会取消鏖战模式。', - }, - separatism: { - name: '群雄割据', - init: false, - frequent: true, - restart: true, - intro: '开放不同势力组合,以优先亮出的武将牌作为自己的势力,双势力武将则使用列表的第一个势力' - }, - initshow_draw: { - name: '首亮奖励', - item: { - 'off': '关闭', - 'draw': '摸牌', - 'mark': '标记', - }, - init: 'mark', - frequent: true, - intro: '第一个明置身份牌的角色可获得摸牌奖励' - }, - viewnext: { - name: '观看下家副将', - init: false, - intro: '若开启此选项,所有的玩家将在挑选武将后,分发起始手牌之前,分别观看自己下家的副将。', - }, - aozhan_bgm: { - updatex: function () { - this.lastChild.innerHTML = this._link.config.item[lib.config.mode_config.guozhan.aozhan_bgm]; - if (!Array.isArray(_status.aozhanBGMToRemove)) return; - const menu = this._link.menu; - for (let i = 0; i < menu.childElementCount; i++) { - const link = menu.childNodes[i]._link; - if (['disabled', 'random'].includes(link) || !_status.aozhanBGMToRemove.includes(link)) continue; - _status.aozhanBGMToRemove.remove(link); - menu.childNodes[i].delete(); - } - }, - name: '鏖战背景音乐', - item: { - disabled: '不启用', - online: 'Online', - rewrite: 'Rewrite', - chaoming: '潮鸣', - random: '随机播放', - }, - init: 'rewrite', - onclick: function (item) { - game.saveConfig('aozhan_bgm', item, this._link.config.mode); - if (_status._aozhan == true) game.playBackgroundMusic(); - }, - }, - zhulian: { - name: '珠联璧合', - init: true, - // frequent:true, - intro: '主将和副将都明置后,若为特定组合,可获得【珠联璧合】标记' - }, - changeViceType: { - name: '副将变更方式', - init: 'default', - item: { - default: '发现式', - online: '随机式', - }, - frequent: true, - restart: true, - }, - onlyguozhan: { - name: '使用国战武将', - init: true, - frequent: true, - restart: true, - intro: '开启武将技能将替换为国战版本并禁用非国战武将' - }, - guozhanSkin: { - name: '使用国战皮肤', - init: true, - frequent: true, - restart: true, - intro: '开启此选项后,将会把有国战专属皮肤的武将替换为国战皮肤' - }, - junzhu: { - name: '替换君主', - init: true, - // frequent:true, - restart: true, - intro: '若开启此选项,玩家的第一个回合开始时,若其主武将牌有对应的君主武将牌,则其可以将此武将牌替换为对应的君主武将牌,然后重新调整体力上限。若玩家的体力上限因此增大,则玩家回复等量的体力。' - }, - double_hp: { - name: '双将体力上限', - init: 'pingjun', - item: { - hejiansan: '和减三', - pingjun: '平均值', - zuidazhi: '最大值', - zuixiaozhi: '最小值', - zonghe: '相加', - }, - restart: true, - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - free_choose: { - name: '自由选将', - init: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - } - }, - onlyguozhanexpand: { - name: '默认展开自由选将', - init: false, - restart: true, - intro: '开启后自由选将对话框将默认显示全部武将' - }, - change_identity: { - name: '自由选择座位', - init: true, - onclick: function (bool) { - game.saveConfig('change_identity', bool, this._link.config.mode); - if (get.mode() != 'guozhan' || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - var dialog; - if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; - else dialog = _status.event.dialog; - if (!_status.brawl || !_status.brawl.noAddSetting) { - if (!dialog.querySelector('table') && get.config('change_identity')) _status.event.getParent().addSetting(dialog); - else _status.event.getParent().removeSetting(dialog); - } - ui.update(); - } - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (get.mode() != 'guozhan' || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - } - }, - change_card: { - name: '开启手气卡', - init: 'disabled', - item: { - disabled: '禁用', - once: '一次', - twice: '两次', - unlimited: '无限', - } - }, - continue_game: { - name: '显示再战', - init: true, - intro: '游戏结束后可选择用相同的武将再进行一局游戏', - onclick: function (bool) { - game.saveConfig('continue_game', bool, this._link.config.mode); - if (get.config('continue_game') && get.mode() == 'guozhan') { - if (!ui.continue_game && _status.over && !_status.brawl && !game.no_continue_game) { - ui.continue_game = ui.create.control('再战', game.reloadCurrent); - } - } - else if (ui.continue_game) { - ui.continue_game.close(); - delete ui.continue_game; - } - } - }, - dierestart: { - name: '死亡后显示重来', - init: true, - onclick: function (bool) { - game.saveConfig('dierestart', bool, this._link.config.mode); - if (get.config('dierestart') && get.mode() == 'guozhan') { - if (!ui.restart && game.me.isDead() && !_status.connectMode) { - ui.restart = ui.create.control('restart', game.reload); - } - } - else if (ui.restart) { - ui.restart.close(); - delete ui.restart; - } - } - }, - revive: { - name: '死亡后显示复活', - init: false, - onclick: function (bool) { - game.saveConfig('revive', bool, this._link.config.mode); - if (get.config('revive') && get.mode() == 'guozhan') { - if (!ui.revive && game.me.isDead()) { - ui.revive = ui.create.control('revive', ui.click.dierevive); - } - } - else if (ui.revive) { - ui.revive.close(); - delete ui.revive; - } - } - }, - difficulty: { - name: 'AI对人类态度', - init: 'normal', - item: { - easy: '友好', - normal: '一般', - hard: '仇视', - } - }, - choice_num: { - name: '候选武将数', - init: '7', - restart: true, - item: { - '5': '五', - '6': '六', - '7': '七', - '8': '八', - '9': '九', - '10': '十', - } - }, - } - }, - versus: { - name: '对决', - connect: { - update: function (config, map) { - if (config.connect_versus_mode == '1v1') { - map.connect_choice_num.show(); - map.connect_replace_number.show(); - } - else { - map.connect_choice_num.hide(); - map.connect_replace_number.hide(); - } - if (config.connect_versus_mode == '2v2' || config.connect_versus_mode == '3v3') { - map.connect_replace_handcard.show(); - } - else { - map.connect_replace_handcard.hide(); - } - }, - connect_versus_mode: { - name: '游戏模式', - init: '1v1', - item: { - '1v1': '1v1', - '2v2': '2v2', - '3v3': '3v3', - '4v4': '4v4', - 'guandu': '官渡', - }, - frequent: true - }, - connect_replace_handcard: { - name: '四号位保护', - init: true, - frequent: true, - intro: '最后行动的角色起始手牌数+1' - }, - connect_olfeiyang_four: { - name: '四号位获得【飞扬】', - init: true, - frequent: true, - intro: '最后行动的角色获得技能【飞扬】(准备阶段,你可以弃置三张牌,然后弃置判定区的一张牌)', - }, - connect_choice_num: { - name: '侯选武将数', - init: '20', - frequent: true, - item: { - '12': '12人', - '16': '16人', - '20': '20人', - '24': '24人', - '40': '40人', - } - }, - connect_replace_number: { - name: '替补人数', - init: '2', - frequent: true, - item: { - '0': '无', - '1': '1人', - '2': '2人', - '3': '3人', - '4': '4人', - '5': '5人', - } - }, - // connect_ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // connect_ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - }, - config: { - update: function (config, map) { - if (config.versus_mode == 'four') { - map.change_choice.hide(); - map.ladder.show(); - if (config.ladder) { - map.ladder_monthly.show(); - map.ladder_reset.show(); - } - else { - map.ladder_monthly.hide(); - map.ladder_reset.hide(); - } - map.enable_all.show(); - map.enable_all_cards_four.show(); - map.four_assign.show(); - map.four_phaseswap.show(); - map.expand_dialog.show(); - map.fouralign.show(); - map.edit_character_four.show(); - map.reset_character_four.show(); - } - else { - map.change_choice.show(); - map.ladder.hide(); - map.ladder_monthly.hide(); - map.ladder_reset.hide(); - map.enable_all.hide(); - map.enable_all_cards_four.hide(); - map.four_assign.hide(); - map.four_phaseswap.hide(); - map.expand_dialog.hide(); - map.fouralign.hide(); - map.edit_character_four.hide(); - map.reset_character_four.hide(); - } - if (config.versus_mode == 'three') { - map.edit_character_three.show(); - map.reset_character_three.show(); - } - else { - map.edit_character_three.hide(); - map.reset_character_three.hide(); - } - if (config.versus_mode == 'three' || config.versus_mode == 'one') { - map.enable_all_three.show(); - map.enable_all_cards.show(); - } - else { - map.enable_all_three.hide(); - map.enable_all_cards.hide(); - } - if (config.versus_mode == 'jiange' || config.versus_mode == 'two' || config.versus_mode == 'endless' || - config.versus_mode == 'three' || config.versus_mode == 'one' || config.versus_mode == 'siguo') { - map.free_choose.show(); - } - else { - map.free_choose.hide(); - } - if (config.versus_mode == 'jiange') { - map.double_character_jiange.show(); - } - else { - map.double_character_jiange.hide(); - } - if (config.versus_mode == 'two') { - map.replace_handcard_two.show(); - map.olfeiyang_four.show(); - map.replace_character_two.show(); - map.two_assign.show(); - map.two_phaseswap.show(); - } - else { - map.replace_handcard_two.hide(); - map.olfeiyang_four.hide(); - map.replace_character_two.hide(); - map.two_assign.hide(); - map.two_phaseswap.hide(); - } - if (config.versus_mode == 'two' || config.versus_mode == 'siguo' || config.versus_mode == 'four') { - if (config.versus_mode == 'four' && (config.four_assign || config.four_phaseswap)) { - map.change_identity.hide(); - } - else { - map.change_identity.show(); - } - } - else { - map.change_identity.hide(); - } - if (config.versus_mode == 'siguo') { - map.siguo_character.show(); - } - else { - map.siguo_character.hide(); - } - }, - versus_mode: { - name: '游戏模式', - init: 'four', - item: { - four: '对抗', - three: '统率', - two: '欢乐', - guandu: '官渡', - jiange: '剑阁', - siguo: '四国', - standard: '自由' - // endless:'无尽', - // triple:'血战', - // one:'1v1', - }, - restart: true, - frequent: true, - }, - ladder: { - name: '天梯模式', - init: true, - frequent: true, - restart: true - }, - ladder_monthly: { - name: '每月重置天梯', - init: true, - frequent: true, - }, - enable_all: { - name: '启用全部武将', - init: false, - frequent: true, - restart: true, - }, - enable_all_cards_four: { - name: '启用全部卡牌', - init: false, - frequent: true, - restart: true, - }, - enable_all_three: { - name: '启用全部武将', - init: false, - frequent: true, - restart: true, - }, - enable_all_cards: { - name: '启用全部卡牌', - init: false, - frequent: true, - restart: true, - }, - four_assign: { - name: '代替队友选将', - init: false, - restart: true, - }, - four_phaseswap: { - name: '代替队友行动', - init: false, - restart: true, - }, - two_assign: { - name: '代替队友选将', - init: false, - restart: true, - }, - two_phaseswap: { - name: '代替队友行动', - init: false, - restart: true, - }, - free_choose: { - name: '自由选将', - init: true, - frequent: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (!ui.create.cheat2) return; - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - } - }, - fouralign: { - name: '自由选择阵型', - init: false - }, - change_identity: { - name: '自由选择座位', - init: true, - onclick: function (bool) { - game.saveConfig('change_identity', bool, this._link.config.mode); - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (_status.mode == 'four') { - if (get.config('four_assign') || get.config('four_phaseswap')) return; - if (bool) { - if (_status.event.parent.addSetting) { - _status.event.parent.addSetting(); - } - } - else { - var seats = _status.event.parent.seatsbutton; - if (seats) { - while (seats.length) { - seats.shift().remove(); - } - delete _status.event.parent.seatsbutton; - } - } - } - else { - var dialog; - if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; - else dialog = _status.event.dialog; - if (!_status.brawl || !_status.brawl.noAddSetting) { - if (!dialog.querySelector('table') && get.config('change_identity')) _status.event.getParent().addSetting(dialog); - else _status.event.getParent().removeSetting(dialog); - } - ui.update(); - } - } - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - }, - frequent: true, - }, - double_character_jiange: { - name: '双将模式', - init: false, - frequent: true, - }, - replace_handcard_two: { - name: '四号位保护', - init: true, - frequent: true, - intro: '最后行动的角色起始手牌+1' - }, - olfeiyang_four: { - name: '四号位获得【飞扬】', - init: true, - frequent: true, - intro: '最后行动的角色获得技能【飞扬】(准备阶段,你可以弃置三张牌,然后弃置判定区的一张牌)', - }, - replace_character_two: { - name: '替补模式', - init: false, - frequent: true, - intro: '每个额外选择一名武将,死亡后用该武将代替重新上场,替补武将用完时失败' - }, - expand_dialog: { - name: '默认展开选将框', - intro: '选将框打开时直接显示全部武将(可能使游戏在开始时卡顿)', - init: false, - }, - siguo_character: { - name: '专属武将出场率', - init: 'increase', - item: { - increase: '大概率', - normal: '默认概率', - off: '不出现', - }, - frequent: true - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true - // }, - ladder_reset: { - name: '重置天梯数据', - onclick: function () { - var node = this; - if (node._clearing) { - game.save('ladder', { - current: 900, - top: 900, - month: (new Date()).getMonth() - }); - ui.ladder.innerHTML = '卫士五'; - clearTimeout(node._clearing); - node.firstChild.innerHTML = '重置天梯数据'; - delete node._clearing; - return; - } - node.firstChild.innerHTML = '单击以确认 (3)'; - node._clearing = setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (2)'; - node._clearing = setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (1)'; - node._clearing = setTimeout(function () { - node.firstChild.innerHTML = '重置天梯数据'; - delete node._clearing; - }, 1000); - }, 1000); - }, 1000); - }, - clear: true, - }, - edit_character_three: { - name: '编辑统率将池', - clear: true, - onclick: function () { - if (get.mode() != 'versus') { - alert('请进入对决模式,然后再编辑将池'); - return; - } - var container = ui.create.div('.popup-container.editor'); - var node = container; - var map = get.config('character_three') || lib.choiceThree; - var str = 'character=[\n '; - for (var i = 0; i < map.length; i++) { - str += '"' + map[i] + '",'; - if (i + 1 < map.length && (i + 1) % 5 == 0) str += '\n '; - } - str += '\n];'; - node.code = str; - ui.window.classList.add('shortcutpaused'); - ui.window.classList.add('systempaused'); - var saveInput = function () { - var code; - if (container.editor) { - code = container.editor.getValue(); - } - else if (container.textarea) { - code = container.textarea.value; - } - try { - var character = null; - eval(code); - if (!Array.isArray(character)) { - throw ('err'); - } - } - catch (e) { - var tip = lib.getErrorTip(e) || ''; - alert('代码语法有错误,请仔细检查(' + e + ')' + tip); - window.focus(); - if (container.editor) { - container.editor.focus(); - } - else if (container.textarea) { - container.textarea.focus(); - } - return; - } - game.saveConfig('character_three', character, 'versus'); - ui.window.classList.remove('shortcutpaused'); - ui.window.classList.remove('systempaused'); - container.delete(); - container.code = code; - delete window.saveNonameInput; - }; - window.saveNonameInput = saveInput; - var editor = ui.create.editor(container, saveInput); - if (node.aced) { - ui.window.appendChild(node); - node.editor.setValue(node.code, 1); - } - else if (lib.device == 'ios') { - ui.window.appendChild(node); - if (!node.textarea) { - var textarea = document.createElement('textarea'); - editor.appendChild(textarea); - node.textarea = textarea; - lib.setScroll(textarea); - } - node.textarea.value = node.code; - } - else { - if (!window.CodeMirror) { - import('../../game/codemirror.js').then(() => { - lib.codeMirrorReady(node, editor); - }); - lib.init.css(lib.assetURL + 'layout/default', 'codemirror'); - } - else { - lib.codeMirrorReady(node, editor); - } - } - }, - }, - reset_character_three: { - name: '重置统率将池', - intro: '将统率三军模式下的将池重置为默认将池', - clear: true, - onclick: function () { - if (confirm('该操作不可撤销!是否清除统率三军模式的自定义将池,并将其重置为默认将池?')) { - game.saveConfig('character_three', null, 'versus'); - alert('将池已重置'); - } - }, - }, - edit_character_four: { - name: '编辑4v4将池', - clear: true, - onclick: function () { - if (get.mode() != 'versus') { - alert('请进入对决模式,然后再编辑将池'); - return; - } - var container = ui.create.div('.popup-container.editor'); - var node = container; - var map = get.config('character_four') || lib.choiceFour; - var str = 'character=[\n '; - for (var i = 0; i < map.length; i++) { - str += '"' + map[i] + '",'; - if (i + 1 < map.length && (i + 1) % 5 == 0) str += '\n '; - } - str += '\n];'; - node.code = str; - ui.window.classList.add('shortcutpaused'); - ui.window.classList.add('systempaused'); - var saveInput = function () { - var code; - if (container.editor) { - code = container.editor.getValue(); - } - else if (container.textarea) { - code = container.textarea.value; - } - try { - var character = null; - eval(code); - if (!Array.isArray(character)) { - throw ('err'); - } - } - catch (e) { - var tip = lib.getErrorTip(e) || ''; - alert('代码语法有错误,请仔细检查(' + e + ')' + tip); - window.focus(); - if (container.editor) { - container.editor.focus(); - } - else if (container.textarea) { - container.textarea.focus(); - } - return; - } - game.saveConfig('character_four', character, 'versus'); - ui.window.classList.remove('shortcutpaused'); - ui.window.classList.remove('systempaused'); - container.delete(); - container.code = code; - delete window.saveNonameInput; - }; - window.saveNonameInput = saveInput; - var editor = ui.create.editor(container, saveInput); - if (node.aced) { - ui.window.appendChild(node); - node.editor.setValue(node.code, 1); - } - else if (lib.device == 'ios') { - ui.window.appendChild(node); - if (!node.textarea) { - var textarea = document.createElement('textarea'); - editor.appendChild(textarea); - node.textarea = textarea; - lib.setScroll(textarea); - } - node.textarea.value = node.code; - } - else { - if (!window.CodeMirror) { - import('../../game/codemirror.js').then(() => { - lib.codeMirrorReady(node, editor); - }); - lib.init.css(lib.assetURL + 'layout/default', 'codemirror'); - } - else { - lib.codeMirrorReady(node, editor); - } - } - }, - }, - reset_character_four: { - name: '重置4v4将池', - intro: '将4v4模式下的将池重置为默认将池', - clear: true, - onclick: function () { - if (confirm('该操作不可撤销!是否清除4v4模式的自定义将池,并将其重置为默认将池?')) { - game.saveConfig('character_four', null, 'versus'); - alert('将池已重置'); - } - }, - }, - } - }, - connect: { - name: '联机', - config: { - connect_nickname: { - name: '联机昵称', - input: true, - frequent: true, - }, - connect_avatar: { - name: '联机头像', - init: 'caocao', - item: {}, - frequent: true, - onclick: function (item) { - game.saveConfig('connect_avatar', item); - game.saveConfig('connect_avatar', item, 'connect'); - } - }, - hall_ip: { - name: '联机大厅', - input: true, - frequent: true, - }, - hall_button: { - name: '联机大厅按钮', - init: true, - frequent: true, - onclick: function (bool) { - game.saveConfig('hall_button', bool, 'connect'); - if (ui.hall_button) { - if (bool) { - ui.hall_button.style.display = ''; - } - else { - ui.hall_button.style.display = 'none'; - } - } - } - }, - wss_mode: { - name: '使用WSS协议', - init: false, - frequent: true, - intro: '在用户填写的IP地址没有直接指定使用WS/WSS协议的情况下,默认使用WSS协议,而非WS协议来连接到联机服务器。
    请不要轻易勾选此项!', - }, - read_clipboard: { - name: '读取邀请链接', - init: false, - frequent: true, - intro: '读取剪贴板以解析邀请链接自动加入联机房间', - } - } - }, - boss: { - name: '挑战', - config: { - free_choose: { - name: '自由选将', - init: true, - frequent: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - } - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - }, - frequent: true, - }, - single_control: { - name: '单人控制', - init: true, - frequent: true, - onclick: function (bool) { - game.saveConfig('single_control', bool, this._link.config.mode); - if (ui.single_swap && game.me != game.boss) { - if (bool) { - ui.single_swap.style.display = 'none'; - } - else { - ui.single_swap.style.display = ''; - } - } - }, - intro: '只控制一名角色,其他角色由AI控制' - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - } - }, - doudizhu: { - name: '斗地主', - connect: { - update: function (config, map) { - if (config.connect_doudizhu_mode == 'online') { - map.connect_change_card.hide(); - } - else { - map.connect_change_card.show(); - } - if (config.connect_doudizhu_mode != 'normal') { - map.connect_double_character.hide(); - } - else { - map.connect_double_character.show(); - } - }, - connect_doudizhu_mode: { - name: '游戏模式', - init: 'normal', - item: { - normal: '休闲', - kaihei: '开黑', - huanle: '欢乐', - binglin: '兵临', - online: '智斗', - }, - restart: true, - frequent: true, - }, - connect_double_character: { - name: '双将模式', - init: false, - frequent: true, - restart: true, - }, - connect_change_card: { - name: '启用手气卡', - init: false, - frequent: true, - restart: true, - }, - }, - config: { - update: function (config, map) { - if (config.doudizhu_mode == 'online') { - map.change_card.hide(); - map.edit_character.show(); - map.reset_character.show(); - } - else { - map.change_card.show(); - map.edit_character.hide(); - map.reset_character.hide(); - } - if (config.doudizhu_mode != 'normal') { - map.double_character.hide(); - map.free_choose.hide(); - map.change_identity.hide(); - map.change_choice.hide(); - map.continue_game.hide(); - map.dierestart.hide(); - map.choice_zhu.hide(); - map.choice_fan.hide(); - map.revive.hide(); - } - else { - map.double_character.show(); - map.free_choose.show(); - map.change_identity.show(); - map.change_choice.show(); - map.continue_game.show(); - map.dierestart.show(); - map.choice_zhu.show(); - map.choice_fan.show(); - map.revive.show(); - } - if (config.double_character && config.doudizhu_mode == 'normal') { - map.double_hp.show(); - } - else { - map.double_hp.hide(); - } - }, - doudizhu_mode: { - name: '游戏模式', - init: 'normal', - item: { - normal: '休闲', - kaihei: '开黑', - huanle: '欢乐', - binglin: '兵临', - online: '智斗', - }, - restart: true, - frequent: true, - }, - double_character: { - name: '双将模式', - init: false, - frequent: true, - restart: true, - }, - double_hp: { - name: '双将体力上限', - init: 'pingjun', - item: { - hejiansan: '和减三', - pingjun: '平均值', - zuidazhi: '最大值', - zuixiaozhi: '最小值', - zonghe: '相加', - }, - restart: true, - }, - free_choose: { - name: '自由选将', - init: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - } - }, - change_identity: { - name: '自由选择身份和座位', - init: true, - onclick: function (bool) { - game.saveConfig('change_identity', bool, this._link.config.mode); - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - var dialog; - if (ui.cheat2 && ui.cheat2.backup) dialog = ui.cheat2.backup; - else dialog = _status.event.dialog; - if (!_status.brawl || !_status.brawl.noAddSetting) { - if (!dialog.querySelector('table') && get.config('change_identity')) _status.event.getParent().addSetting(dialog); - else _status.event.getParent().removeSetting(dialog); - } - ui.update(); - } - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - } - }, - change_card: { - name: '开启手气卡', - init: 'disabled', - item: { - disabled: '禁用', - once: '一次', - twice: '两次', - unlimited: '无限', - }, - }, - continue_game: { - name: '显示再战', - init: false, - onclick: function (bool) { - game.saveConfig('continue_game', bool, this._link.config.mode); - if (get.config('continue_game')) { - if (!ui.continue_game && _status.over && !_status.brawl && !game.no_continue_game) { - ui.continue_game = ui.create.control('再战', game.reloadCurrent); - } - } - else if (ui.continue_game) { - ui.continue_game.close(); - delete ui.continue_game; - } - }, - intro: '游戏结束后可选择用相同的武将再进行一局游戏' - }, - dierestart: { - name: '死亡后显示重来', - init: true, - onclick: function (bool) { - game.saveConfig('dierestart', bool, this._link.config.mode); - if (get.config('dierestart')) { - if (!ui.restart && game.me.isDead() && !_status.connectMode) { - ui.restart = ui.create.control('restart', game.reload); - } - } - else if (ui.restart) { - ui.restart.close(); - delete ui.restart; - } - } - }, - revive: { - name: '死亡后显示复活', - init: false, - onclick: function (bool) { - game.saveConfig('revive', bool, this._link.config.mode); - if (get.config('revive')) { - if (!ui.revive && game.me.isDead()) { - ui.revive = ui.create.control('revive', ui.click.dierevive); - } - } - else if (ui.revive) { - ui.revive.close(); - delete ui.revive; - } - } - }, - choice_zhu: { - name: '地主候选武将数', - init: '3', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - choice_fan: { - name: '农民候选武将数', - init: '3', - restart: true, - item: { - '3': '三', - '4': '四', - '5': '五', - '6': '六', - '8': '八', - '10': '十', - }, - }, - edit_character: { - name: '编辑将池', - clear: true, - onclick: function () { - if (get.mode() != 'doudizhu') { - alert('请进入斗地主模式,然后再编辑将池'); - return; - } - var container = ui.create.div('.popup-container.editor'); - var node = container; - var map = get.config('character_online') || lib.characterOnline; - node.code = 'character=' + get.stringify(map) + '\n/*\n 这里是智斗三国模式的武将将池。\n 您可以在这里编辑对武将将池进行编辑,然后点击“保存”按钮即可保存。\n 将池中的Key势力武将,仅同时在没有被禁用的情况下,才会出现在选将框中。\n 而非Key势力的武将,只要所在的武将包没有被隐藏,即可出现在选将框中。\n 该将池为单机模式/联机模式通用将池。在这里编辑后,即使进入联机模式,也依然会生效。\n 但联机模式本身禁用的武将(如神貂蝉)不会出现在联机模式的选将框中。\n*/'; - ui.window.classList.add('shortcutpaused'); - ui.window.classList.add('systempaused'); - var saveInput = function () { - var code; - if (container.editor) { - code = container.editor.getValue(); - } - else if (container.textarea) { - code = container.textarea.value; - } - try { - var character = null; - eval(code); - if (!get.is.object(character)) { - throw ('err'); - } - var groups = []; - for (var i in character) { - if (!Array.isArray(character[i])) throw ('type'); - if (character[i].length >= 3) groups.push(i); - } - if (groups.length < 3) throw ('enough'); - } - catch (e) { - if (e == 'type') { - alert('请严格按照格式填写,不要写入不为数组的数据'); - } - else if (e == 'enough') { - alert('请保证至少写入了3个势力,且每个势力至少有3个武将'); - } - else if (e == 'err') { - alert('代码格式有错误,请对比示例代码仔细检查'); - } - else { - var tip = lib.getErrorTip(e) || ''; - alert('代码语法有错误,请仔细检查(' + e + ')' + tip); - } - window.focus(); - if (container.editor) { - container.editor.focus(); - } - else if (container.textarea) { - container.textarea.focus(); - } - return; - } - game.saveConfig('character_online', character, 'doudizhu'); - ui.window.classList.remove('shortcutpaused'); - ui.window.classList.remove('systempaused'); - container.delete(); - container.code = code; - delete window.saveNonameInput; - }; - window.saveNonameInput = saveInput; - var editor = ui.create.editor(container, saveInput); - if (node.aced) { - ui.window.appendChild(node); - node.editor.setValue(node.code, 1); - } - else if (lib.device == 'ios') { - ui.window.appendChild(node); - if (!node.textarea) { - var textarea = document.createElement('textarea'); - editor.appendChild(textarea); - node.textarea = textarea; - lib.setScroll(textarea); - } - node.textarea.value = node.code; - } - else { - if (!window.CodeMirror) { - import('../../game/codemirror.js').then(() => { - lib.codeMirrorReady(node, editor); - }); - lib.init.css(lib.assetURL + 'layout/default', 'codemirror'); - } - else { - lib.codeMirrorReady(node, editor); - } - } - }, - }, - reset_character: { - name: '重置将池', - intro: '将智斗三国模式下的将池重置为默认将池', - clear: true, - onclick: function () { - if (confirm('该操作不可撤销!是否清除智斗三国模式的自定义将池,并将其重置为默认将池?')) { - game.saveConfig('character_online', null, 'doudizhu'); - alert('将池已重置'); - } - }, - }, - } - }, - single: { - name: '单挑', - connect: { - connect_single_mode: { - name: '游戏模式', - init: 'normal', - item: { - normal: '新1v1', - dianjiang: '点将单挑', - changban: '血战长坂坡', - }, - restart: true, - frequent: true, - }, - connect_enable_jin: { - name: '启用晋势力武将', - init: false, - restart: true, - frequent: true, - }, - update: function (config, map) { - if (config.connect_single_mode != 'normal') { - map.connect_enable_jin.hide(); - } - else { - map.connect_enable_jin.show(); - } - }, - }, - config: { - single_mode: { - name: '游戏模式', - init: 'normal', - item: { - normal: '新1v1', - dianjiang: '点将单挑', - changban: '血战长坂坡', - }, - restart: true, - frequent: true, - }, - enable_jin: { - name: '启用晋势力武将', - init: false, - restart: true, - frequent: true, - }, - update: function (config, map) { - if (config.single_mode != 'normal') { - map.enable_jin.hide(); - } - else { - map.enable_jin.show(); - } - }, - } - }, - chess: { - name: '战棋', - config: { - chess_mode: { - name: '游戏模式', - init: 'combat', - item: { - combat: '自由', - three: '统率', - leader: '君主', - }, - restart: true, - frequent: true, - }, - update: function (config, map) { - if (config.chess_mode == 'leader') { - map.chess_leader_save.show(); - map.chess_leader_clear.show(); - map.chess_leader_allcharacter.show(); - map.chess_character.hide(); - } - else { - map.chess_leader_save.hide(); - map.chess_leader_clear.hide(); - map.chess_leader_allcharacter.hide(); - map.chess_character.show(); - } - if (config.chess_mode == 'combat') { - // map.battle_number.show(); - // map.chess_ordered.show(); - map.free_choose.show(); - map.change_choice.show(); - } - else { - // map.battle_number.hide(); - // map.chess_ordered.hide(); - map.free_choose.hide(); - map.change_choice.hide(); - } - // if(config.chess_mode!='leader'){ - // map.ban_weak.show(); - // map.ban_strong.show(); - // } - // else{ - // map.ban_weak.hide(); - // map.ban_strong.hide(); - // } - }, - chess_leader_save: { - name: '选择历程', - init: 'save1', - item: { - save1: '一', - save2: '二', - save3: '三', - save4: '四', - save5: '五', - }, - restart: true, - frequent: true, - }, - chess_leader_allcharacter: { - name: '启用全部角色', - init: true, - onclick: function (bool) { - if (confirm('调整该设置将清除所有进度,是否继续?')) { - for (var i = 1; i < 6; i++) game.save('save' + i, null, 'chess'); - game.saveConfig('chess_leader_allcharacter', bool, 'chess'); - if (get.mode() == 'chess') game.reload(); - return; - } - else this.classList.toggle('on'); - }, - }, - chess_leader_clear: { - name: '清除进度', - onclick: function () { - var node = this; - if (node._clearing) { - for (var i = 1; i < 6; i++) game.save('save' + i, null, 'chess'); - game.reload(); - return; - } - node._clearing = true; - node.firstChild.innerHTML = '单击以确认 (3)'; - setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (2)'; - setTimeout(function () { - node.firstChild.innerHTML = '单击以确认 (1)'; - setTimeout(function () { - node.firstChild.innerHTML = '清除进度'; - delete node._clearing; - }, 1000); - }, 1000); - }, 1000); - }, - clear: true, - frequent: true, - }, - // chess_treasure:{ - // name:'战场机关', - // init:'0', - // frequent:true, - // item:{ - // '0':'关闭', - // '0.1':'较少出现', - // '0.2':'偶尔出现', - // '0.333':'时常出现', - // '0.5':'频繁出现', - // } - // }, - chess_obstacle: { - name: '随机路障', - init: '0.2', - item: { - '0': '关闭', - '0.2': '少量', - '0.333': '中量', - '0.5': '大量', - }, - frequent: true, - }, - show_range: { - name: '显示卡牌范围', - init: true, - }, - show_distance: { - name: '显示距离', - init: true, - }, - chess_character: { - name: '战棋武将', - init: true, - frequent: true, - }, - chess_card: { - name: '战棋卡牌', - init: true, - frequent: true, - }, - free_choose: { - name: '自由选将', - init: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - }, - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - }, - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - chessscroll_speed: { - name: '边缘滚动速度', - init: '20', - intro: '鼠标移至屏幕边缘时自动滚屏', - item: { - '0': '不滚动', - '10': '10格/秒', - '20': '20格/秒', - '30': '30格/秒', - } - }, - } - }, - tafang: { - name: '塔防', - config: { - tafang_turn: { - name: '游戏胜利', - init: '10', - frequent: true, - item: { - '10': '十回合', - '20': '二十回合', - '30': '三十回合', - '1000': '无限', - } - }, - // tafang_size:{ - // name:'战场大小', - // init:'9', - // frequent:true, - // item:{ - // '6':'小', - // '9':'中', - // '12':'大', - // } - // }, - tafang_difficulty: { - name: '战斗难度', - init: '2', - frequent: true, - item: { - '1': '简单', - '2': '普通', - '3': '困难', - } - }, - show_range: { - name: '显示卡牌范围', - init: true, - }, - show_distance: { - name: '显示距离', - init: true, - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - chessscroll_speed: { - name: '边缘滚动速度', - intro: '鼠标移至屏幕边缘时自动滚屏', - init: '20', - item: { - '0': '不滚动', - '10': '10格/秒', - '20': '20格/秒', - '30': '30格/秒', - } - }, - } - }, - brawl: { - name: '乱斗', - config: { - huanhuazhizhan: { - name: '幻化之战', - init: true, - frequent: true - }, - duzhansanguo: { - name: '毒战三国', - init: true, - frequent: true - }, - daozhiyueying: { - name: '导师月英', - init: true, - frequent: true - }, - weiwoduzun: { - name: '唯我独尊', - init: true, - frequent: true - }, - tongxingzhizheng: { - name: '同姓之争', - init: true, - frequent: true - }, - jiazuzhizheng: { - name: '家族之争', - init: true, - frequent: true - }, - tongqueduopao: { - name: '铜雀夺袍', - init: true, - frequent: true - }, - tongjiangmoshi: { - name: '同将模式', - init: true, - frequent: true - }, - baiyidujiang: { - name: '白衣渡江', - init: true, - frequent: true - }, - qianlidanji: { - name: '千里单骑', - init: true, - frequent: true - }, - liangjunduilei: { - name: '两军对垒', - init: true, - frequent: true - }, - scene: { - name: '创建场景', - init: true, - frequent: true - } - } - }, - stone: { - name: '炉石', - config: { - // update:function(config,map){ - // if(config.stone_mode=='deck'){ - // // map.deck_length.show(); - // // map.deck_repeat.show(); - // map.random_length.hide(); - // map.skill_bar.show(); - // } - // else{ - // // map.deck_length.hide(); - // // map.deck_repeat.hide(); - // map.random_length.show(); - // map.skill_bar.hide(); - // } - // }, - // stone_mode:{ - // name:'游戏模式', - // init:'deck', - // item:{ - // deck:'构筑', - // random:'随机' - // }, - // restart:true, - // frequent:true, - // }, - // deck_length:{ - // name:'卡组长度', - // init:'30', - // item:{ - // '30':'30张', - // '50':'50张', - // '80':'80张', - // }, - // frequent:true, - // }, - // deck_repeat:{ - // name:'重复卡牌', - // init:'2', - // item:{ - // '2':'2张', - // '3':'3张', - // '5':'5张', - // '80':'无限', - // }, - // frequent:true, - // }, - // random_length:{ - // name:'随从牌数量', - // init:'1/80', - // item:{ - // '1/120':'少', - // '1/80':'中', - // '1/50':'多', - // }, - // frequent:true, - // }, - battle_number: { - name: '出场人数', - init: '1', - frequent: true, - item: { - '1': '一人', - '2': '两人', - '3': '三人', - '4': '四人', - '6': '六人', - '8': '八人', - '10': '十人', - }, - onclick: function (num) { - game.saveConfig('battle_number', num, this._link.config.mode); - if (_status.connectMode) return; - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (_status.event.getParent().changeDialog) { - _status.event.getParent().changeDialog(); - } - }, - }, - mana_mode: { - name: '行动值变化', - init: 'inc', - item: { - inf: '涨落', - inc: '递增' - }, - frequent: true - }, - skill_bar: { - name: '怒气值', - init: true, - frequent: true, - restart: true, - }, - double_character: { - name: '双将模式', - init: false, - frequent: true, - restart: function () { - return _status.event.getParent().name != 'chooseCharacter' || _status.event.name != 'chooseButton'; - } - }, - free_choose: { - name: '自由选将', - init: true, - onclick: function (bool) { - game.saveConfig('free_choose', bool, this._link.config.mode); - if (_status.connectMode) return; - if (get.mode() != this._link.config.mode || !_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat2 && get.config('free_choose')) ui.create.cheat2(); - else if (ui.cheat2 && !get.config('free_choose')) { - ui.cheat2.close(); - delete ui.cheat2; - } - }, - }, - change_choice: { - name: '开启换将卡', - init: true, - onclick: function (bool) { - game.saveConfig('change_choice', bool, this._link.config.mode); - if (_status.connectMode) return; - if (!_status.event.getParent().showConfig && !_status.event.showConfig) return; - if (!ui.cheat && get.config('change_choice')) ui.create.cheat(); - else if (ui.cheat && !get.config('change_choice')) { - ui.cheat.close(); - delete ui.cheat; - } - }, - }, - // ban_weak:{ - // name:'屏蔽弱将', - // init:true, - // restart:true, - // }, - // ban_strong:{ - // name:'屏蔽强将', - // init:false, - // restart:true, - // }, - } - }, - }; - static status = { - running: false, - canvas: false, - time: 0, - reload: 0, - delayed: 0, - frameId: 0, - videoId: 0, - globalId: 0, - }; - static help = { - '关于游戏': '
    关于无名杀