From 8e361409a44d807ecc3a6f31a8972f6141554cf5 Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Tue, 17 Oct 2023 22:06:24 -0700 Subject: [PATCH 1/6] Revert `get.itemtype`. --- game/game.js | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/game/game.js b/game/game.js index d01e14879..1c8eeb4a2 100644 --- a/game/game.js +++ b/game/game.js @@ -30415,7 +30415,7 @@ */ this.nature=suitOrCard[3]; } - else if(suitOrCard instanceof lib.element.Card){ + else if(get.itemtype(suitOrCard)=='card'){ this.name=get.name(suitOrCard); this.suit=get.suit(suitOrCard); this.color=get.color(suitOrCard); @@ -58780,12 +58780,12 @@ } return func; }, - eventInfoOL:(item,level,noMore)=>item instanceof lib.element.Event?`_noname_event:${JSON.stringify(Object.entries(item).reduce((stringifying,entry)=>{ + eventInfoOL:(item,level,noMore)=>get.itemtype(item)=='event'?`_noname_event:${JSON.stringify(Object.entries(item).reduce((stringifying,entry)=>{ const key=entry[0]; if(key=='_trigger'){ if(noMore!==false) stringifying[key]=get.eventInfoOL(entry[1],null,false); } - else if(!lib.element.Event.prototype[key]&&key!='content'&&!(entry[1] instanceof lib.element.Event)) stringifying[key]=get.stringifiedResult(entry[1],null,false); + else if(!lib.element.Event.prototype[key]&&key!='content'&&get.itemtype(entry[1])!='event') stringifying[key]=get.stringifiedResult(entry[1],null,false); return stringifying; },{}))}`:'', /** @@ -59018,11 +59018,15 @@ if(isPosition) return 'divposition'; } } - if(obj instanceof lib.element.Button) return 'button'; - if(obj instanceof lib.element.Card) return 'card'; - if(obj instanceof lib.element.Player) return 'player'; - if(obj instanceof lib.element.Dialog) return 'dialog'; - if(obj instanceof lib.element.Event) return 'event'; + if(get.objtype(obj)=='div'){ + if(obj.classList.contains('button')) return 'button'; + if(obj.classList.contains('card')) return 'card'; + if(obj.classList.contains('player')) return 'player'; + if(obj.classList.contains('dialog')) return 'dialog'; + } + if(get.is.object(obj)){ + if(obj.isMine==lib.element.Event.prototype.isMine) return 'event'; + } }, equipNum:card=>{ if(get.type(card)=='equip'){ @@ -59164,7 +59168,7 @@ if(typeof card=='string') return card.split(lib.natureSeparator).sort(lib.sort.nature).join(lib.natureSeparator); if(Array.isArray(card)) return card.sort(lib.sort.nature).join(lib.natureSeparator); var nature=card.nature; - if(player instanceof lib.element.Player||player!==false){ + if(get.itemtype(player)=='player'||player!==false){ var owner=get.owner(card); if(owner){ return game.checkMod(card,owner,nature,'cardnature',owner); From 9d8bf314b4be5899e461e47a672c7545a5150895 Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Thu, 19 Oct 2023 02:45:39 -0700 Subject: [PATCH 2/6] Support more players and identities. --- game/game.js | 525 ++++++++++++++++++++++++++++-------- layout/newlayout/global.css | 9 - mode/identity.js | 498 +++++++++++----------------------- 3 files changed, 567 insertions(+), 465 deletions(-) diff --git a/game/game.js b/game/game.js index 1c8eeb4a2..aa38dfbda 100644 --- a/game/game.js +++ b/game/game.js @@ -432,8 +432,11 @@ }, } }, - //Yingbian - //应变 + /** + * Yingbian + * + * 应变 + */ yingbian:{ condition:{ color:new Map([ @@ -605,8 +608,32 @@ ['all','无视条件执行所有选项'] ]) }, - //The actual card name - //实际的卡牌名称 + /** + * Stratagem buff + * + * 谋攻强化 + */ + stratagemBuff:{ + buff:new Map([ + ['sha',[1,'require']], + ['shan',[1,'double']], + ['juedou',[2,'damage']], + ['huogong',[2,'damage']], + ['tao',[3,'double']] + ]), + prompt:new Map([ + ['sha','响应时所需【闪】数+1。'], + ['shan','视为两张【闪】的效果。'], + ['juedou','对目标造成的伤害+1。'], + ['huogong','造成的伤害+1。'], + ['tao','回复值+1。'] + ]) + }, + /** + * The actual card name + * + * 实际的卡牌名称 + */ actualCardName:new Map([ ['挟令','挟天子以令诸侯'], ['霹雳投石车','霹雳车'] @@ -4875,11 +4902,11 @@ name:'身份', connect:{ update:function(config,map){ - if(config.connect_identity_mode=='mougong'){ - map.connect_round1_use_nuqi.show(); + if(config.connect_identity_mode=='stratagem'){ + map.connect_round_one_use_fury.show(); } else{ - map.connect_round1_use_nuqi.hide(); + map.connect_round_one_use_fury.hide(); } if(config.connect_identity_mode=='zhong'){ map.connect_player_number.hide(); @@ -4890,7 +4917,7 @@ map.connect_special_identity.hide(); map.connect_double_character.show(); } - else if(config.connect_identity_mode=='mougong'){ + else if(config.connect_identity_mode=='stratagem'){ map.connect_double_character.show(); map.connect_player_number.show(); map.connect_limit_zhu.hide(); @@ -4935,7 +4962,7 @@ item:{ normal:'标准', zhong:'明忠', - mougong:'谋攻', + stratagem:'谋攻', purple:'3v3v2', }, restart:true, @@ -4945,14 +4972,8 @@ connect_player_number:{ name:'游戏人数', init:'8', - item:{ - '2':'两人', - '3':'三人', - '4':'四人', - '5':'五人', - '6':'六人', - '7':'七人', - '8':'八人' + get item(){ + return lib.mode.identity.config.player_number.item; }, frequent:true, restart:true, @@ -4980,7 +5001,9 @@ init:false, restart:true, // frequent:true, - intro:'开启后游戏中将有两个内奸(内奸胜利条件仍为主内1v1时击杀主公)' + get intro(){ + return lib.mode.identity.config.double_nei.intro; + } }, connect_double_character:{ name:'双将模式', @@ -5001,7 +5024,7 @@ frequent:true, intro:'开启后游戏中将增加军师、大将、贼首三个身份' }, - connect_round1_use_nuqi:{ + connect_round_one_use_fury:{ name:'开启首轮强化卡牌', init:false, frequent:false, @@ -5027,12 +5050,12 @@ }, config:{ update:function(config,map){ - if(config.identity_mode=='mougong'){ - map.round1_use_nuqi.show(); + if(config.identity_mode=='stratagem'){ + map.round_one_use_fury.show(); map.nei_auto_mark_camouflage.show(); } else{ - map.round1_use_nuqi.hide(); + map.round_one_use_fury.hide(); map.nei_auto_mark_camouflage.hide(); } if(config.identity_mode=='zhong'){ @@ -5064,7 +5087,7 @@ } map.continue_game.show(); } - else if(config.identity_mode=='mougong'){ + else if(config.identity_mode=='stratagem'){ map.continue_game.show(); map.player_number.show(); map.enhance_zhu.hide(); @@ -5188,7 +5211,7 @@ item:{ normal:'标准', zhong:'明忠', - mougong:'谋攻', + stratagem:'谋攻', purple:'3v3v2', }, restart:true, @@ -5198,14 +5221,12 @@ player_number:{ name:'游戏人数', init:'8', - item:{ - '2':'两人', - '3':'三人', - '4':'四人', - '5':'五人', - '6':'六人', - '7':'七人', - '8':'八人' + get item(){ + const minimumNumberOfPlayers=2,maximumNumberOfPlayers=Math.max(_status.maximumNumberOfPlayers||10,minimumNumberOfPlayers),item={}; + for(let playerNumber=minimumNumberOfPlayers;playerNumber<=maximumNumberOfPlayers;playerNumber++){ + item[playerNumber]=`${get.cnNumber(playerNumber)}人`; + } + return item; }, frequent:true, restart:true, @@ -5215,7 +5236,7 @@ init:false, restart:true, frequent:true, - intro:'开启后游戏中将有两个内奸(内奸胜利条件仍为主内1v1时击杀主公)' + intro:'若游戏人数不大于8,则开启后游戏中将有两个内奸(内奸胜利条件仍为主内1v1时击杀主公)' }, choose_group:{ name:'神武将选择势力', @@ -5361,7 +5382,7 @@ unlimited:'无限', }, }, - round1_use_nuqi:{ + round_one_use_fury:{ name:'开启首轮强化卡牌', init:false, frequent:false, @@ -5562,13 +5583,8 @@ connect_player_number:{ name:'游戏人数', init:'8', - item:{ - '3':'三人', - '4':'四人', - '5':'五人', - '6':'六人', - '7':'七人', - '8':'八人' + get item(){ + return lib.mode.guozhan.config.player_number.item; }, frequent:true, restart:true, @@ -5653,13 +5669,12 @@ player_number:{ name:'游戏人数', init:'8', - item:{ - '3':'三人', - '4':'四人', - '5':'五人', - '6':'六人', - '7':'七人', - '8':'八人' + get item(){ + const minimumNumberOfPlayers=3,maximumNumberOfPlayers=Math.max(_status.maximumNumberOfPlayers||10,minimumNumberOfPlayers),item={}; + for(let playerNumber=minimumNumberOfPlayers;playerNumber<=maximumNumberOfPlayers;playerNumber++){ + item[playerNumber]=`${get.cnNumber(playerNumber)}人`; + } + return item; }, frequent:true, restart:true, @@ -11097,11 +11112,15 @@ } }, layout:function(layout,nosave){ + const previousTransitionDuration=document.body.style.transitionDuration; + document.body.style.transitionDuration='1s'; + const previousFilter=document.body.style.filter,previousWebkitFilter=document.body.style.webkitFilter; + document.body.style.filter=document.body.style.webkitFilter='brightness(0)'; if(layout=='default') layout='mobile'; if(!nosave) game.saveConfig('layout',layout); game.layout=layout; ui.arena.hide(); - setTimeout(function(){ + new Promise(resolve=>setTimeout(resolve,500)).then(()=>{ if(game.layout=='default'){ ui.css.layout.href=''; } @@ -11196,17 +11215,26 @@ } ui.updatej(); ui.updatem(); - setTimeout(function(){ - ui.arena.show(); - if(game.me) game.me.update(); - setTimeout(function(){ - ui.updatex(); - },500); - setTimeout(function(){ - ui.updatec(); - },1000); - },100); - },500); + return new Promise(resolve=>setTimeout(resolve,100)); + }).then(()=>{ + ui.arena.show(); + if(game.me) game.me.update(); + return new Promise(resolve=>setTimeout(resolve,500)); + }).then(()=>{ + ui.updatex(); + ui.create.playerPositions(); + return new Promise(resolve=>setTimeout(resolve,500)); + }).then(()=>{ + ui.updatec(); + if(previousFilter) document.body.style.filter=previousFilter; + else document.body.style.removeProperty('filter'); + if(previousWebkitFilter) document.body.style.webkitFilter=previousWebkitFilter; + else document.body.style.removeProperty('-webkit-filter'); + return new Promise(resolve=>setTimeout(resolve,1000)); + }).then(()=>{ + if(previousTransitionDuration) document.body.style.transitionDuration=previousTransitionDuration; + else document.body.style.removeProperty('transition-duration'); + }); }, background:function(){ if(lib.config.image_background_random){ @@ -12302,6 +12330,7 @@ cooperation_use_info:'双方累计使用至少4种花色的牌', charge:'蓄力值', expandedSlots:'扩展装备栏', + _stratagem_add_buff:'强化' }, element:{ content:{ @@ -27991,7 +28020,7 @@ var player=this,mode=get.mode(); if(!this.isZhu) return false; if(mode=='identity'){ - if(_status.mode=='mougong'&&!this.identityShown) return false; + if(_status.mode=='stratagem'&&!this.identityShown) return false; return true; } if(mode=='versus'&&(_status.mode=='four'||_status.mode=='guandu')) return true; @@ -30396,7 +30425,6 @@ * @param {string} [nature] */ constructor(suitOrCard,numberOrCards,name,nature){ - if(typeof suitOrCard=='undefined'&&typeof numberOrCards=='undefined'&&typeof name=='undefined'&&typeof nature=='undefined') return; if(Array.isArray(suitOrCard)){ /** * @type {string} @@ -32436,6 +32464,217 @@ } }, skill:{ + _stratagem_add_buff:{ + enable:'chooseToUse', + filter:function(event,player){ + if(!event.stratagemSettings) return false; + if(game.roundNumber<2&&!event.stratagemSettings.roundOneUseFury) return false; + var cards=player.getCards('hs'); + var names=Array.from(lib.stratagemBuff.buff.keys()); + if(!names.length) return false; + for(var card of cards){ + if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; + for(var name of names){ + var myName=get.name(card,player),nature=get.nature(card,player); + if(name==myName){ + if(event.filterCard({name:name,nature:nature,isCard:true,cards:[card]},player,event)){ + if(player.storage.stratagem_fury>=lib.stratagemBuff.buff.get(name)[0]) + return true; + } + } + } + } + return false; + }, + onChooseToUse:function(event){ + if(!event.stratagemSettings&&!game.online){ + event.set('stratagemSettings',{ + roundOneUseFury:_status.connectMode?lib.configOL.round_one_use_fury:get.config('round_one_use_fury') + }); + } + }, + check:function(card){ + var player=_status.event.player; + if(_status.event.type=='phase'){ + var name=get.name(card,player); + if(name=='sha'){ + if(game.hasPlayer(current=>{ + return player.canUse(card,current)&&(player.storage.zhibi&&!player.storage.zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(player.storage.stratagem_fury||0)-1)))&¤t.mayHaveShan()&&player.hasSkill('jiu'); + })) return 1; + return 0; + } else if(name=='tao'){ + if(player.hp<=2&&player.getDamagedHp()>=2) return 1; + return 0; + } + return 1; + } + else if(_status.event.type=='dying') return get.attitude(player,_status.event.dying)>3?1:0; + return (_status.event.getParent().shanRequired||1)>1&&get.damageEffect(player,_status.event.getParent().player||player,player)<0?1:0; + }, + position:'hs', + filterCard:function(card,player,event){ + event=event||_status.event; + var filter=event._backup.filterCard; + var names=Array.from(lib.stratagemBuff.buff.keys()); + for(var name of names){ + var myName=get.name(card,player),nature=get.nature(card,player); + if(name==myName){ + if(filter({name:name,nature:nature,isCard:true,cards:[card]},player,_status.event)){ + if(player.storage.stratagem_fury>=lib.stratagemBuff.buff.get(name)[0]){ + return true; + } + } + } + } + return false; + }, + viewAs:function(cards,player){ + var name=get.name(cards[0],player); + var nature=get.nature(cards[0],player); + if(name){ + return { + name:name, + nature:nature, + suit:get.suit(cards[0],player), + number:get.number(cards[0],player), + isCard:true, + cards:[cards[0]], + storage:{stratagemBuffed:1}, + }; + } + return null; + }, + prompt:()=>{ + const span=document.createElement('span'); + span.classList.add('text'); + span.style.fontFamily='yuanli'; + const stratagemBuff=lib.stratagemBuff,buff=stratagemBuff.buff; + stratagemBuff.prompt.forEach((prompt,cardName)=>{ + const li=document.createElement('li'); + li.innerHTML=`【${get.translation(cardName)}】:${buff.get(cardName)[0]}点怒气。${prompt}`; + span.appendChild(li); + }); + return `当你需要使用位于“强化表”内的非虚拟卡牌时,你可以消耗对应数量的怒气将其强化并使用。${document.createElement('hr').outerHTML}${span.outerHTML}`; + }, + precontent:function(){ + 'step 0' + player.changeFury(-lib.stratagemBuff.buff.get(event.result.card.name)[0]); + }, + ai:{ + order:function(item,player){ + var player=player||_status.event.player; + if(_status.event.type=='phase'){ + var cards=player.getCards('hs'); + for(var card of cards){ + if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; + var name=get.name(card,player); + if(name=='sha'){ + if(game.hasPlayer(current=>{ + return player.canUse(card,current)&&(player.storage.zhibi&&!player.storage.zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(player.storage.stratagem_fury||0)-1)))&¤t.mayHaveShan(); + })) return get.order(card,player)+0.5; + } else if(name=='tao'){ + if(player.hp<=2&&player.getDamagedHp()>=2) return get.order(card,player)+0.5; + } + return 8; + } + } + return 3.5; + }, + }, + subSkill:{ + sha:{ + trigger:{player:'useCardToPlayered'}, + forced:true, + silent:true, + popup:false, + charlotte:true, + filter:function(event,player){ + return event.card.name=='sha'&&event.card.storage&&event.card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get('sha')[1]=='require'&&!event.getParent().directHit.contains(event.target); + }, + content:function(){ + if(!trigger.card.storage.stratagem_logged){ + game.log(player,'触发了强化杀的效果'); + game.log('#y'+get.translation(trigger.card),'需要额外使用一张','#y【闪】','响应'); + trigger.card.storage.stratagem_logged=true; + } + var id=trigger.target.playerid; + var map=trigger.getParent().customArgs; + if(!map[id]) map[id]={}; + if(typeof map[id].shanRequired=='number'){ + map[id].shanRequired++; + } + else{ + map[id].shanRequired=2; + } + }, + ai:{ + directHit_ai:true, + skillTagFilter:function(player,tag,arg){ + if(arg.card.name!='sha'||(arg.card&&arg.card.storage&&!arg.card.storage.stratagemBuffed)||(arg.target.countCards('h','shan')>=1&&!arg.target.storage.stratagem_fury)) return false; + }, + }, + }, + shan:{ + trigger:{ + player:'shanEnd', + }, + forced:true, + silent:true, + popup:false, + charlotte:true, + filter:function(event,player){ + return event.getParent(3).name=='sha'&&event.getParent().card.storage&&event.getParent().card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get('shan')[1]=='double'; + }, + content:function(event,player){ + if(!trigger.card.storage.stratagem_logged){ + game.log(player,'触发了强化闪的效果'); + game.log('#y'+get.translation(trigger.card),'视为两张','#y【闪】','的效果'); + trigger.card.storage.stratagem_logged=true; + } + if(trigger.getParent(3).shanRequired) trigger.getParent(3).shanRequired--; + } + }, + damage:{ + trigger:{player:'damageBegin1'}, + forced:true, + silent:true, + popup:false, + charlotte:true, + filter:function(event,player){ + if(!event.card) return false; + var names=Array.from(lib.stratagemBuff.buff.keys()),name=event.card.name; + return names.contains(name)&&event.getParent(2).player==event.source&&event.card.storage&&event.card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get(name)[1]=='damage'; + }, + content:function(){ + if(!trigger.card.storage.stratagem_logged){ + game.log(player,'触发了强化'+get.translation(trigger.card.name)+'的效果'); + game.log('#y'+get.translation(trigger.card),'造成的伤害','#y+1'); + trigger.card.storage.stratagem_logged=true; + } + trigger.num++; + } + }, + tao:{ + trigger:{player:'useCard'}, + filter:function(event,player){ + return event.card.name=='tao'&&event.card.storage&&event.card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get('tao')[1]=='double'; + }, + forced:true, + silent:true, + popup:false, + charlotte:true, + content:function(){ + if(!trigger.card.storage.stratagem_logged){ + game.log(player,'触发了强化桃的效果'); + game.log('#y'+get.translation(trigger.card),'的回复值','#y+1'); + trigger.card.storage.stratagem_logged=true; + } + if(!trigger.baseDamage) trigger.baseDamage=1; + trigger.baseDamage++; + }, + } + } + }, expandedSlots:{ markimage:'image/card/expandedSlots.png', intro:{ @@ -37095,7 +37334,7 @@ ui.updatehl(); for(var i=0;inew lib.element.Player(position,noclick), - connectPlayers:function(ip){ + /** + * @author curpond + * @author Tipx-L + * @param {number} [numberOfPlayers] + */ + connectPlayerPositions:numberOfPlayers=>{ + if(typeof numberOfPlayers!='number') numberOfPlayers=lib.configOL.number; + if(!numberOfPlayers) return; + const playerPositions=ui.playerPositions; + while(playerPositions.length){ + playerPositions.pop().remove(); + } + const temporaryPlayer=ui.create.div('.player.connect',ui.window).hide(); + const computedStyle=getComputedStyle(temporaryPlayer); + const halfWidth=parseFloat(computedStyle.width)/2; + const halfHeight=parseFloat(computedStyle.height)/2; + temporaryPlayer.remove(); + const halfNumberOfPlayers=Math.round(numberOfPlayers/2); + const upperPercentage=100/(halfNumberOfPlayers+1); + const scale=10/numberOfPlayers; + for(let ordinal=0;ordinal.player.connect[data-position='${ordinal}']{`, + `left:calc(${upperPercentage*(ordinal+1)}% - ${halfWidth}px);`, + `top:calc(${100/3}% - ${halfHeight}px);`, + scale<1?`transform:scale(${scale});`:'', + '}' + ].join(''))); + } + const lowerPercentage=100/(numberOfPlayers-halfNumberOfPlayers+1); + for(let ordinal=halfNumberOfPlayers;ordinal.player.connect[data-position='${ordinal}']{`, + `left:calc(${lowerPercentage*(ordinal-halfNumberOfPlayers+1)}% - ${halfWidth}px);`, + `top:calc(${100*2/3}% - ${halfHeight}px);`, + scale<1?`transform:scale(${scale});`:'', + '}' + ].join(''))); + } + }, + connectPlayers:ip=>{ + ui.create.connectPlayerPositions(); game.connectPlayers=[]; - for(var i=0;i<8;i++){ - var player=ui.create.player(ui.window); - player.dataset.position=i; + const numberOfPlayers=lib.configOL.number; + for(let position=0;position=lib.configOL.number){ - player.classList.add('unselectable2'); - } } var bar=ui.create.div(ui.window); @@ -52621,7 +52904,7 @@ for(var i of game.connectPlayers){ if(!i.nickname&&!i.classList.contains('unselectable2')) num++; } - if(num>=lib.configOL.number-1){ + if(num>=numberOfPlayers-1){ alert('至少要有两名玩家才能开始游戏!'); return; } @@ -52637,52 +52920,76 @@ ui.connectStartButton=button; ui.connectStartBar=bar; }, - players:function(num){ - if(num===0){ + /** + * @author curpond + * @author Tipx-L + * @param {number} [numberOfPlayers] + */ + playerPositions:numberOfPlayers=>{ + if(typeof numberOfPlayers!='number') numberOfPlayers=ui.arena.dataset.number; + //当人数小于8时,还是用以前的布局。 + if(!numberOfPlayers||numberOfPlayers<9) return; + const playerPositions=ui.playerPositions; + while(playerPositions.length){ + playerPositions.pop().remove(); + } + //单个人物的宽度。这里要设置玩家的实际的宽度 + const temporaryPlayer=ui.create.div('.player',ui.arena).hide(); + const computedStyle=getComputedStyle(temporaryPlayer); + const scale=8/numberOfPlayers; + //玩家顶部距离父容器上边缘的距离偏移的单位距离 + const oneThirdHeight=parseFloat(computedStyle.height)/3*scale; + const halfWidth=parseFloat(computedStyle.width)/2; + temporaryPlayer.remove(); + //列数,即假如8人场,除去自己后,上面7个人占7列 + const columnCount=numberOfPlayers-1; + const percentage=100/numberOfPlayers; + //仅当游戏人数大于8人,且玩家的座位号大于0时,设置玩家的位置。因为0号位是game.me在最下方,无需设置。 + for(let ordinal=1;ordinal.player[data-position='${ordinal}']{`, + `left:calc(${percentage*(reversedOrdinal+1)}% - ${halfWidth}px);`, + `top:${top}px;`, + `transform:scale(${scale});`, + '}' + ].join(''))); + } + }, + players:numberOfPlayers=>{ + if(numberOfPlayers===0){ return; } - if(num==undefined) num=lib.configOL.number; - if(num==undefined) num=get.playerNumber(); - if(typeof num=='string'){ - num=parseInt(num); + if(numberOfPlayers==undefined) numberOfPlayers=lib.configOL.number; + if(numberOfPlayers==undefined) numberOfPlayers=get.playerNumber(); + if(typeof numberOfPlayers=='string'){ + numberOfPlayers=parseInt(numberOfPlayers); } - if(!num) num=5; - for(var i=0;i0){ - players[i].previous=players[i-1]; - players[i].previousSeat=players[i-1]; + const players=game.players; + for(let ordinal=0;ordinal0){ + players[ordinal].previous=players[ordinal-1]; + players[ordinal].previousSeat=players[ordinal-1]; } - if(iui.arena.appendChild(player)); return players; }, me:function(hasme){ @@ -53487,7 +53794,7 @@ if(!game.getIdentityList) return; if(_status.video) return; if(this.parentNode.forceShown) return; - if(!_status.connectMode&&this.parentNode.ai.mougong_camouflage&&get.config('nei_auto_mark_camouflage')&&game.me.identity=='nei') return; + if(!_status.connectMode&&this.parentNode.ai.stratagem_camouflage&&get.config('nei_auto_mark_camouflage')&&game.me.identity=='nei') return; if(_status.clickingidentity){ for(var i=0;i<_status.clickingidentity[1].length;i++){ _status.clickingidentity[1][i].delete(); @@ -58405,7 +58712,7 @@ switch(config.identity_mode){ case 'purple':return '三对三对二'; case 'zhong':return (config.double_character?'双将':'')+'忠胆英杰'; - case 'mougong':return get.cnNumber(parseInt(config.number))+'人'+(config.double_character?'双将':'')+'谋攻'; + case 'stratagem':return get.cnNumber(parseInt(config.number))+'人'+(config.double_character?'双将':'')+'谋攻'; default:return get.cnNumber(parseInt(config.number))+'人'+(config.double_character?'双将':'')+'身份'; } } diff --git a/layout/newlayout/global.css b/layout/newlayout/global.css index 691d4bc6e..d80186a42 100644 --- a/layout/newlayout/global.css +++ b/layout/newlayout/global.css @@ -452,15 +452,6 @@ /*--------位置(1人)------*/ .player[data-position='0']{top:calc(100% - 170px);left:calc(50% - 75px);} /*--------位置(联机)------*/ -#window>.player.connect[data-position='0']{left:calc(200% / 7 - 1200px / 7);top:calc(300% / 7 - 160px + 5px);} -#window>.player.connect[data-position='1']{left:calc(300% / 7 - 750px / 7);top:calc(300% / 7 - 160px + 5px);} -#window>.player.connect[data-position='2']{left:calc(400% / 7 - 300px / 7);top:calc(300% / 7 - 160px + 5px);} -#window>.player.connect[data-position='3']{left:calc(500% / 7 + 150px / 7);top:calc(300% / 7 - 160px + 5px);} -#window>.player.connect[data-position='4']{left:calc(200% / 7 - 1200px / 7);top:calc(400% / 7 - 40px + 5px);} -#window>.player.connect[data-position='5']{left:calc(300% / 7 - 750px / 7);top:calc(400% / 7 - 40px + 5px);} -#window>.player.connect[data-position='6']{left:calc(400% / 7 - 300px / 7);top:calc(400% / 7 - 40px + 5px);} -#window>.player.connect[data-position='7']{left:calc(500% / 7 + 150px / 7);top:calc(400% / 7 - 40px + 5px);} - #window>.player.connect[data-position='c0']{left:calc(50% - 255px);top:calc(50% - 90px)} #window>.player.connect[data-position='c1']{left:calc(50% - 75px);top:calc(50% - 90px)} #window>.player.connect[data-position='c2']{left:calc(50% + 105px);top:calc(50% - 90px)} diff --git a/mode/identity.js b/mode/identity.js index eb53477b4..9e21e21e6 100644 --- a/mode/identity.js +++ b/mode/identity.js @@ -234,8 +234,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ game.players[i].ai.shown=0; } } - var isMougong=_status.mode=='mougong'; - if(isMougong){ + var stratagemMode=_status.mode=='stratagem'; + if(stratagemMode){ var beginner; if(_status.cheat_seat){ var seat=_status.cheat_seat.link; @@ -248,47 +248,30 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } event.beginner=beginner; - _status.mougong_buff={ - sha:[1,'require'], - shan:[1,'double'], - juedou:[2,'damage'], - huogong:[2,'damage'], - tao:[3,'double'], + var stratagemBroadcast=()=>{ + _status.stratagemFuryMax=3; + ui.css.stratagemCardStyle=lib.init.sheet([ + '.card.stratagem-fury-glow:before{', + 'opacity:0.2;', + 'box-shadow:rgba(0,0,0,0.2) 0 0 0 1px,rgb(255,109,12) 0 0 5px,rgb(255,0,0) 0 0 10px;', + 'background-color:yellow;', + '-webkit-filter:blur(5px);', + 'filter:blur(5px);', + '}' + ].join('')); }; - game.broadcastAll(function(){ - _status.mougong_nuqi_max=3; - var mougong_cardStyle=document.createElement('style'); - document.head.appendChild(mougong_cardStyle); - mougong_cardStyle.innerHTML='.card.mougong_nuqi_glow:before{opacity:0.2;box-shadow:rgba(0,0,0,0.2) 0 0 0 1px,rgb(255,109,12) 0 0 5px,rgb(255,0,0) 0 0 10px;background-color:yellow;-webkit-filter:blur(5px);filter:blur(5px);}'; - ui.css.mougong_cardStyle=mougong_cardStyle; - }); - if(_status.connectMode){ - _status.round1_use_nuqi=lib.configOL.round1_use_nuqi; - if(!_status.postReconnect.mougong_reinit){ - _status.postReconnect.mougong_reinit=[ - function(){ - _status.mougong_nuqi_max=3; - var mougong_cardStyle=document.createElement('style'); - document.head.appendChild(mougong_cardStyle); - mougong_cardStyle.innerHTML='.card.mougong_nuqi_glow:before{opacity:0.2;box-shadow:rgba(0,0,0,0.2) 0 0 0 1px,rgb(255,109,12) 0 0 5px,rgb(255,0,0) 0 0 10px;background-color:yellow;-webkit-filter:blur(5px);filter:blur(5px);}'; - ui.css.mougong_cardStyle=mougong_cardStyle; - },{} - ]; - } - } - else{ - _status.round1_use_nuqi=get.config('round1_use_nuqi'); - } + game.broadcastAll(stratagemBroadcast); + if(_status.connectMode&&!_status.postReconnect.stratagemReinit) _status.postReconnect.stratagemReinit=[stratagemBroadcast,{}]; for(var current of game.players){ - if(current.identity=='zhu') current.addSkill('mougong_showZhu'); - if(current.identity=='fan') current.addSkill('mougong_showFan'); + if(current.identity=='zhu') current.addSkill('stratagem_show_zhu'); + if(current.identity=='fan') current.addSkill('stratagem_show_fan'); } } if(game.zhu==game.me&&game.zhu.identity!='zhu'&&_status.brawl&&_status.brawl.identityShown){ delete game.zhu; } else{ - if(!isMougong) game.zhu.ai.shown=1; + if(!stratagemMode) game.zhu.ai.shown=1; if(game.zhu2){ game.zhong=game.zhu; game.zhu=game.zhu2; @@ -302,10 +285,10 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } var enhance_zhu=false; if(_status.connectMode){ - enhance_zhu=(!['zhong','mougong','purple'].includes(_status.mode)&&lib.configOL.enhance_zhu&&get.population('fan')>=3); + enhance_zhu=(!['zhong','stratagem','purple'].includes(_status.mode)&&lib.configOL.enhance_zhu&&get.population('fan')>=3); } else{ - enhance_zhu=(!['zhong','mougong','purple'].includes(_status.mode)&&get.config('enhance_zhu')&&get.population('fan')>=3); + enhance_zhu=(!['zhong','stratagem','purple'].includes(_status.mode)&&get.config('enhance_zhu')&&get.population('fan')>=3); } if(enhance_zhu){ var skill; @@ -341,18 +324,18 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ name2:players[i].name2, identity:players[i].identity }; - if(isMougong){ + if(stratagemMode){ ifo.translate=lib.translate[game.players[i].name]; - ifo.isCamouflaged=players[i].ai.mougong_camouflage; + ifo.isCamouflaged=players[i].ai.stratagemCamouflage; } info.push(ifo); } _status.videoInited=true; game.addVideo('init',null,info); - if(isMougong){ + if(stratagemMode){ game.addVideo('arrangeLib',null,{ skill:{ - mougong_nuqi:{ + stratagem_fury:{ mark:true, marktext:'🔥', intro:{ @@ -363,13 +346,13 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }, }); for(var i=0;i5) return 5; return 4; @@ -434,8 +417,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ uiintro.add('
游戏模式:'+(lib.configOL.identity_mode=='zhong'?'明忠':'标准')); uiintro.add('
双将模式:'+(lib.configOL.double_character?'开启':'关闭')); if(lib.configOL.identity_mode!='zhong'){ - if(lib.configOL.identity_mode=='mougong'){ - uiintro.add('
首轮强化:'+(lib.configOL.round1_use_nuqi?'开启':'关闭')); + if(lib.configOL.identity_mode=='stratagem'){ + uiintro.add('
首轮强化:'+(lib.configOL.round_one_use_fury?'开启':'关闭')); } else{ uiintro.add('
双内奸:'+(lib.configOL.double_nei?'开启':'关闭')); @@ -494,7 +477,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } } - else if(_status.mode=='mougong'){ + else if(_status.mode=='stratagem'){ if(game.zhu&&game.zhu.isZhu&&game.zhu.identityShown||game.me.identity=='zhu'){ return { fan:'反', @@ -553,7 +536,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ switch(_status.mode){ case 'purple':str2='3v3v2 - '+(game.me.identity.indexOf('r')==0?'暖色':'冷色')+lib.translate[game.me.identity+'2'];break; case 'zhong':str2='忠胆英杰 - '+lib.translate[game.me.identity+'2'];break; - case 'mougong':str2=get.cnNumber(get.playerNumber())+'人谋攻'+'-'+lib.translate[game.me.identity+'2']; + case 'stratagem':str2=get.cnNumber(get.playerNumber())+'人谋攻'+'-'+lib.translate[game.me.identity+'2']; default:str2=get.cnNumber(get.playerNumber())+'人'+ get.translation(lib.config.mode)+' - '+lib.translate[game.me.identity+'2'] } @@ -1066,14 +1049,13 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ },500); }); }, - chooseCharacterMougongOL:function(){ + chooseCharacterStratagemOL:function(){ var next=game.createEvent('chooseCharacter'); next.setContent(function(){ 'step 0' ui.arena.classList.add('choose-character'); var i; - var identityList; - identityList=lib.config.mode_config.identity.identity[game.players.length-2].slice(0); + var identityList=get.identityList(game.players.length); if(lib.configOL.double_nei){ switch(lib.configOL.number){ case 8: @@ -1286,14 +1268,14 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ _status.characterlist.remove(game.players[i].name2); } - var list=['mougong_nuqi','mougong_nuqi_dongcha','mougong_expose','mougong_addBuff','mougong_addBuff_sha','mougong_addBuff_shan','mougong_addBuff_tao','mougong_addBuff_damage','mougong_shanAi','mougong_cardEffect']; + var list=['stratagem_fury','stratagem_fury_insight','stratagem_expose','stratagem_shan_ai','stratagem_card_effect']; for(var i=0;i{ current.storage.zhibi=[]; current.storage.zhibi_for=[]; - current.markSkill('mougong_nuqi'); + current.markSkill('stratagem_fury'); }); setTimeout(function(){ @@ -1309,8 +1291,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ var next=game.createEvent('chooseCharacter'); next.showConfig=true; next.addPlayer=function(player){ - var list=lib.config.mode_config.identity.identity[game.players.length-3].slice(0); - var list2=lib.config.mode_config.identity.identity[game.players.length-2].slice(0); + var list=get.identityList(game.players.length-1); + var list2=get.identityList(game.players.length); for(var i=0;i4){ + if(!event.stratagemMode&&game.me==game.zhu&&game.players.length>4){ game.me.hp++; game.me.maxHp++; game.me.update(); } for(var i=0;i{ i.storage.zhibi=[]; i.storage.zhibi_for=[]; - i.markSkill('mougong_nuqi'); + i.markSkill('stratagem_fury'); }); } setTimeout(function(){ @@ -2129,8 +2111,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ game.chooseCharacterPurpleOL(); return; } - else if(_status.mode=='mougong'){ - game.chooseCharacterMougongOL(); + else if(_status.mode=='stratagem'){ + game.chooseCharacterStratagemOL(); return; } var next=game.createEvent('chooseCharacter'); @@ -2144,7 +2126,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ identityList=['zhu','zhong','mingzhong','nei','fan','fan','fan','fan']; } else{ - identityList=lib.config.mode_config.identity.identity[game.players.length-2].slice(0); + identityList=get.identityList(game.players.length); if(lib.configOL.double_nei){ switch(lib.configOL.number){ case 8: @@ -2611,33 +2593,31 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ sheshen:'舍身', sheshen_info:'锁定技,主公处于濒死状态即将死亡时,令主公+1体力上限,回复体力至X点(X为你的体力值数),获得你的所有牌,然后你死亡。', yexinbilu:'野心毕露', - mougong_nuqi:'怒气', - mougong_nuqi_dongcha:'洞察', - mougong_addBuff:'强化', - mougong_addBuff_info:'当你需要使用位于“强化表”内的非虚拟卡牌时,你可以消耗对应数量的怒气将其强化并使用。

  • 【杀】 :1点怒气。响应时所需【闪】数+1。
  • 【闪】 :1点怒气。视为两张【闪】的效果。
  • 【决斗】:2点怒气。对目标造成的伤害+1。
  • 【火攻】:2点怒气。造成的伤害+1。
  • 【桃】 :3点怒气。回复值+1。', - mougong_nuqi_cost1:'1🔥', - mougong_nuqi_cost2:'2🔥', - mougong_nuqi_cost3:'3🔥', + stratagem_fury:'怒气', + stratagem_fury_insight:'洞察', + stratagem_fury_cost1:'1🔥', + stratagem_fury_cost2:'2🔥', + stratagem_fury_cost3:'3🔥', }, element:{ player:{ - dongcha:function(target){ - var next=game.createEvent('mougongDongcha'); + insightInto:function(target){ + var next=game.createEvent('stratagemInsight'); next.player=this; next.target=target; - next.setContent('mougongDongcha'); + next.setContent('stratagemInsight'); return next; }, - changeNuqi:function(num){ + changeFury:function(num){ var player=this; - if(!player.storage.mougong_nuqi) player.storage.mougong_nuqi=0; - var tmp=player.storage.mougong_nuqi; - player.storage.mougong_nuqi+=num; - player.storage.mougong_nuqi=Math.max(Math.min(player.storage.mougong_nuqi,_status.mougong_nuqi_max),0); - var del=player.storage.mougong_nuqi-tmp; + if(!player.storage.stratagem_fury) player.storage.stratagem_fury=0; + var tmp=player.storage.stratagem_fury; + player.storage.stratagem_fury+=num; + player.storage.stratagem_fury=Math.max(Math.min(player.storage.stratagem_fury,_status.stratagemFuryMax),0); + var del=player.storage.stratagem_fury-tmp; if(del===0) return; game.log(player,del>=0?'获得了':'失去了',get.cnNumber(Math.abs(del))+'点怒气'); - player.markSkill('mougong_nuqi'); + player.markSkill('stratagem_fury'); }, addExpose:function(num){ if(!game.zhu||!game.zhu.isZhu||!game.zhu.identityShown) return; @@ -2691,7 +2671,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } }, dieAfter2:function(source){ - if(_status.mode=='mougong') return; + if(_status.mode=='stratagem') return; if(_status.mode=='purple'){ if(source){ if(this.identity=='rZhu'||this.identity=='bZhu'){ @@ -2831,8 +2811,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }, logAi:function(targets,card){ if(this.ai.shown==1||this.isMad()) return; - var isMougong=get.mode()=='identity'&&_status.mode=='mougong'; - if(isMougong&&(!game.zhu||!game.zhu.isZhu||!game.zhu.identityShown)) return; + var stratagemMode=get.mode()=='identity'&&_status.mode=='stratagem'; + if(stratagemMode&&(!game.zhu||!game.zhu.isZhu||!game.zhu.identityShown)) return; if(typeof targets=='number'){ this.ai.shown+=targets; } @@ -2879,11 +2859,11 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ else this.ai.shown-=0.1; } } - if(!isMougong&&this!=game.me) this.ai.shown*=2; + if(!stratagemMode&&this!=game.me) this.ai.shown*=2; if(this.ai.shown>0.95) this.ai.shown=0.95; if(this.ai.shown<-0.5) this.ai.shown=-0.5; if(_status.mode=='purple') return; - if(isMougong) return; + if(stratagemMode) return; var marknow=(!_status.connectMode&&this!=game.me&&get.config('auto_mark_identity')&&this.ai.identity_mark!='finished'); // if(true){ @@ -2984,17 +2964,17 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } }, content:{ - mougongDongcha:function(event,map){ + stratagemInsight:function(event,map){ 'step 0' // var player=map.player,target=map.target; - if(!player.storage.mougong_nuqi){event.finish();return;} - // yield player.changeNuqi(-1); - player.changeNuqi(-1); + if(!player.storage.stratagem_fury){event.finish();return;} + // yield player.changeFury(-1); + player.changeFury(-1); 'step 1' if(!player.storage.zhibi) player.storage.zhibi=[]; if(!player.storage.zhibi.contains(target)) player.storage.zhibi.push(target); - var res=get.dongchaResult(player,target); - event.dongcha_result=res; + var res=get.insightResult(player,target); + event.insightResult=res; event.videoId=lib.status.videoId++; var send=(target,res,id)=>{ @@ -3032,7 +3012,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ game.broadcastAll('closeDialog',event.videoId); if(!_status.connectMode&&get.config('auto_mark_identity')&&!target.node.identity.firstChild.innerHTML.length){ game.broadcastAll(function(player,target,event){ - if(player.isUnderControl(true)) target.setIdentity(event.dongcha_result); + if(player.isUnderControl(true)) target.setIdentity(event.insightResult); },player,target,event); } }, @@ -3046,7 +3026,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } var target=list.randomGet(); event.target=target; - target.ai.mougong_camouflage=true; + target.ai.stratagemCamouflage=true; var neis=game.filterPlayer(i=>i.identity=='nei'); if(event.players.includes(game.me)&&game.me.identity=='nei'){ var str=get.translation(target)+'是反贼
    '; @@ -3090,7 +3070,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } var target=list.randomGet(); - target.ai.mougong_camouflage=true; + target.ai.stratagemCamouflage=true; event.videoId=lib.status.videoId++; event.ai_targets=[]; var time=10000; @@ -3179,7 +3159,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(from==to||to.identityShown||from.storage.zhibi&&from.storage.zhibi.contains(to)||(_status.yeconfirm&&['rYe','bYe'].contains(to.identity)&&['rYe','bYe'].contains(to.identity))) return real*1.1; return ((to.ai.shown+0.1)*real+(from.identity.slice(0,1)==to.identity.slice(0,1)?3:-3)*(1-to.ai.shown)) } - else if(_status.mode=='mougong'){ + else if(_status.mode=='stratagem'){ var x=0,num=0,temp,i; if(_status.ai.customAttitude){ for(i=0;i<_status.ai.customAttitude.length;i++){ @@ -3195,15 +3175,15 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } var real=get.realAttitude(from,to),zhibi=from.storage.zhibi,zhibi_for=from.storage.zhibi_for,followCamouflage=true; if(to.ai.shown) return to.ai.shown*(real+(from.identity==to.identity||from.identity=='zhu'&&to.identity=='zhong'||from.identity=='zhong'&&to.identity=='zhu'||(to.identity=='nei'&&get.situation()<=0&&['zhu','zhong'].contains(from.identity)||get.situation()>=3&&from.identity=='fan')?3:-3)) - if(from==to||to.identityShown||((zhibi_for&&zhibi_for.contains(to))||(zhibi&&zhibi.contains(to)))&&!to.ai.mougong_camouflage) return real*1.1; - if(from.identity=='nei'&&to.ai.mougong_camouflage) return real*1.1; + if(from==to||to.identityShown||((zhibi_for&&zhibi_for.contains(to))||(zhibi&&zhibi.contains(to)))&&!to.ai.stratagemCamouflage) return real*1.1; + if(from.identity=='nei'&&to.ai.stratagemCamouflage) return real*1.1; if(to.identity=='nei'){ if(from.identity=='fan'){ if(get.population('zhong')==0){ if(zhibi){ var dead=game.dead.slice(); for(var current of dead){ - if(from.storage.zhibi.contains(current)&¤t.ai.mougong_camouflage){ + if(from.storage.zhibi.contains(current)&¤t.ai.stratagemCamouflage){ if(from.storage.zhibi_for&&from.storage.zhibi_for.contains(to)) return -7; } } @@ -3214,7 +3194,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } if(to.identity=='fan'&&from.identity=='nei'&&zhibi.contains(game.zhu)&&game.players.filter(i=>i!=from&&!zhibi.contains(i)).map(i=>i.identity).reduce((p,c)=>(!p.contains(c)?(p.push(c)&&p):p),[]).length==1) return real; for(var fan of game.dead){ - if(fan.identity!='fan'||!fan.storage.mougong_showFan) continue; + if(fan.identity!='fan'||!fan.storage.stratagem_show_fan) continue; for(var current of fan.storage.zhibi_for){ if(to==current){ return real; @@ -3222,14 +3202,14 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } if(from.identity=='fan'&&to.identity=='fan'){ - if(from.ai.mougong_camouflage){ + if(from.ai.stratagemCamouflage){ var zhu=game.zhu&&game.zhu.isZhu&&game.zhu.identityShown?game.zhu:undefined; if(zhu){ if(zhu.storage.zhibi_for&&zhu.storage.zhibi_for.contains(to)) return 0; } if(zhibi&&zhibi.contains(to)) return -7; } - if(to.ai.mougong_camouflage){ + if(to.ai.stratagemCamouflage){ var zhu=game.zhu&&game.zhu.isZhu&&game.zhu.identityShown?game.zhu:undefined; if(zhu){ if(zhu.storage.zhibi_for&&zhu.storage.zhibi_for.contains(to)) return 0; @@ -3237,12 +3217,12 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(zhibi&&zhibi.contains(to)) return -7; } } - if(from.identity!='nei'&&zhibi&&zhibi.contains(to)&&!to.identityShown&&(followCamouflage&&to.ai.mougong_camouflage)) return -5; + if(from.identity!='nei'&&zhibi&&zhibi.contains(to)&&!to.identityShown&&(followCamouflage&&to.ai.stratagemCamouflage)) return -5; if(from.identity!='nei'&&zhibi_for&&zhibi_for.contains(to)&&!to.identityShown) return -5; if(zhibi){ for(var to2 of zhibi){ if(to2.storage.zhibi_for){ - if(to2.ai.mougong_camouflage){ + if(to2.ai.stratagemCamouflage){ for(var to3 of to2.storage.zhibi_for){ if(zhibi.slice().addArray(zhibi_for).contains(to3)){ if(to==to2){ @@ -3315,7 +3295,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ return -7; } } - else if(_status.mode=='mougong'){ + else if(_status.mode=='stratagem'){ if(!game.zhu){ if(from.identity=='nei'||to.identity=='nei') return -1; if(from.identity==to.identity) return 6; @@ -3718,17 +3698,42 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } return result; }, - dongchaResult:function(from,to){ + insightResult:function(from,to){ var friend='friend',enemy='enemy'; if(from.identity=='nei') return to.identity; if(to.identity=='nei') return friend; - if(from.ai.mougong_camouflage||to.ai.mougong_camouflage) return enemy; + if(from.ai.stratagemCamouflage||to.ai.stratagemCamouflage) return enemy; if(from.identity==to.identity||from.identity=='zhu'&&to.identity=='zhong'||from.identity=='zhong'&&to.identity=='zhu') return friend; return enemy; }, + /** + * @param {number} numberOfPlayers + * @returns {string[]} + */ + identityList:numberOfPlayers=>{ + const modeConfig=lib.config.mode_config; + if(modeConfig){ + const identityConfig=modeConfig.identity; + if(identityConfig){ + const identityLists=identityConfig.identity; + if(identityLists){ + const identityList=identityLists[numberOfPlayers-2]; + if(Array.isArray(identityList)) return identityList.slice(); + } + } + } + const numberOfPlayersExceptLord=numberOfPlayers-1,numberOfLoyalists=Math.round(numberOfPlayersExceptLord*3/9),numberOfSpys=Math.round(numberOfPlayersExceptLord*2/9); + return ['zhu'].concat(Array.from({ + length:numberOfLoyalists + },()=>'zhong'),Array.from({ + length:numberOfSpys + },()=>'nei'),Array.from({ + length:numberOfPlayersExceptLord-numberOfLoyalists-numberOfSpys + },()=>'fan')); + } }, skill:{ - mougong_nuqi:{ + stratagem_fury:{ mark:true, marktext:'🔥', silent:true, @@ -3738,16 +3743,16 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ player:['phaseBegin','damageEnd'], }, content:function(){ - player.changeNuqi(trigger.name=='damage'?trigger.num:1); + player.changeFury(trigger.name=='damage'?trigger.num:1); }, intro:{ name:'怒气', content:function(storage,player){ - return '当前怒气值:'+(storage||0)+'/'+_status.mougong_nuqi_max; + return '当前怒气值:'+(storage||0)+'/'+_status.stratagemFuryMax; }, }, subSkill:{ - dongcha:{ + insight:{ trigger:{ source:'damageSource', global:'loseHpEnd', @@ -3758,7 +3763,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(event.name=='loseHp'){ if(event.getParent()._trigger) source=event.getParent()._trigger.source; } - return player==source&&player.storage.mougong_nuqi>0&&event.player&&event.player.isIn()&&event.player!=player; + return player==source&&player.storage.stratagem_fury>0&&event.player&&event.player.isIn()&&event.player!=player; }, logTarget:'player', prompt2:function(event,player){ @@ -3771,7 +3776,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }, content:function(){ game.log(player,'洞察了',trigger.player,'与其的阵营关系'); - player.dongcha(trigger.player); + player.insightInto(trigger.player); }, ai:{ order:15, @@ -3779,7 +3784,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }, } }, - mougong_showZhu:{ + stratagem_show_zhu:{ trigger:{ player:['dying','phaseBefore'], global:'dieAfter', @@ -3793,13 +3798,13 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ charlotte:true, ruleSkill:true, filter:function(event,player){ - if(player.storage.mougong_showZhu) return false; + if(player.storage.stratagem_show_zhu) return false; if(player.identity=='zhu'){ if(event.player==player){ if(event.name=='dying') return true; - return game.roundNumber>=3; + return game.roundNumber>=Math.max(Math.round(get.totalPopulation()/2),3); } - if(event.name=='die') return game.dead.length>=2; + if(event.name=='die') return game.dead.length>=Math.max(Math.round(get.totalPopulation()/3),2); } return false; }, @@ -3807,7 +3812,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ 'step 0' if(trigger.name=='dying') game.delayx(); 'step 1' - player.storage.mougong_showZhu=true; + player.storage.stratagem_show_zhu=true; game.zhu=game.zhu||player; game.broadcastAll(function(player){ game.zhu=player; @@ -3842,7 +3847,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } }, - mougong_showFan:{ + stratagem_show_fan:{ trigger:{ player:'dying', }, @@ -3852,13 +3857,13 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ charlotte:true, ruleSkill:true, filter:function(event,player){ - return player.ai.mougong_camouflage&&event.player==player&&!game.dead.length&&player.storage.mougong_nuqi>=2&&!player.storage.mougong_showFan; + return player.ai.stratagemCamouflage&&event.player==player&&!game.dead.length&&player.storage.stratagem_fury>=2&&!player.storage.stratagem_show_fan; }, content:function(){ 'step 0' game.delayx(); 'step 1' - player.storage.mougong_showFan=true; + player.storage.stratagem_show_fan=true; game.broadcastAll(function(player){ player.identityShown=true; player.ai.shown=1; @@ -3870,7 +3875,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ game.delay(2); player.playerfocus(800); 'step 2' - player.changeNuqi(-player.storage.mougong_nuqi); + player.changeFury(-player.storage.stratagem_fury); player.discard(player.getCards('hej')); player.link(false); player.turnOver(false); @@ -3878,208 +3883,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ player.draw(3); } }, - mougong_addBuff:{ - enable:'chooseToUse', - filter:function(event,player){ - if(!event.mougong_settings) return false; - if(game.roundNumber<2&&!event.mougong_settings.round1_use_nuqi) return false; - var cards=player.getCards('hs'); - if(!event.mougong_settings.mougong_buff) return false; - var names=Object.keys(event.mougong_settings.mougong_buff); - if(!names.length) return false; - for(var card of cards){ - if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; - for(var name of names){ - var myName=get.name(card,player),nature=get.nature(card,player); - if(name==myName){ - if(event.filterCard({name:name,nature:nature,isCard:true,cards:[card]},player,event)){ - if(player.storage.mougong_nuqi>=event.mougong_settings.mougong_buff[name][0]) - return true; - } - } - } - } - return false; - }, - onChooseToUse:function(event){ - if(!event.mougong_settings&&!game.online){ - event.set('mougong_settings',{ - round1_use_nuqi:_status.round1_use_nuqi, - mougong_buff:_status.mougong_buff, - }); - } - }, - check:function(card){ - var player=_status.event.player; - if(_status.event.type=='phase'){ - var name=get.name(card,player); - if(name=='sha'){ - if(game.hasPlayer(current=>{ - return player.canUse(card,current)&&(player.storage.zhibi&&!player.storage.zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(player.storage.mougong_nuqi||0)-1)))&¤t.mayHaveShan()&&player.hasSkill('jiu'); - })) return 1; - return 0; - } else if(name=='tao'){ - if(player.hp<=2&&player.getDamagedHp()>=2) return 1; - return 0; - } - return 1; - } - else if(_status.event.type=='dying') return get.attitude(player,_status.event.dying)>3?1:0; - return (_status.event.getParent().shanRequired||1)>1&&get.damageEffect(player,_status.event.getParent().player||player,player)<0?1:0; - }, - position:'hs', - filterCard:function(card,player,event){ - event=event||_status.event; - var filter=event._backup.filterCard; - var names=Object.keys(event.mougong_settings.mougong_buff); - for(var name of names){ - var myName=get.name(card,player),nature=get.nature(card,player); - if(name==myName){ - if(filter({name:name,nature:nature,isCard:true,cards:[card]},player,_status.event)){ - if(player.storage.mougong_nuqi>=event.mougong_settings.mougong_buff[name][0]){ - return true; - } - } - } - } - return false; - }, - viewAs:function(cards,player){ - var name=get.name(cards[0],player); - var nature=get.nature(cards[0],player); - if(name){ - return { - name:name, - nature:nature, - suit:get.suit(cards[0],player), - number:get.number(cards[0],player), - isCard:true, - cards:[cards[0]], - storage:{mougong_buffed:true}, - }; - } - return null; - }, - precontent:function(){ - 'step 0' - player.changeNuqi(-_status.mougong_buff[event.result.card.name][0]); - }, - ai:{ - order:function(item,player){ - var player=player||_status.event.player; - if(_status.event.type=='phase'){ - var cards=player.getCards('hs'); - for(var card of cards){ - if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; - var name=get.name(card,player); - if(name=='sha'){ - if(game.hasPlayer(current=>{ - return player.canUse(card,current)&&(player.storage.zhibi&&!player.storage.zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(player.storage.mougong_nuqi||0)-1)))&¤t.mayHaveShan(); - })) return get.order(card,player)+0.5; - } else if(name=='tao'){ - if(player.hp<=2&&player.getDamagedHp()>=2) return get.order(card,player)+0.5; - } - return 8; - } - } - return 3.5; - }, - }, - subSkill:{ - sha:{ - trigger:{player:'useCardToPlayered'}, - forced:true, - silent:true, - popup:false, - charlotte:true, - filter:function(event,player){ - return event.card.name=='sha'&&event.card.storage&&event.card.storage.mougong_buffed&&_status.mougong_buff['sha'][1]=='require'&&!event.getParent().directHit.contains(event.target); - }, - content:function(){ - if(!trigger.card.storage.mougong_logged){ - game.log(player,'触发了强化杀的效果'); - game.log('#y'+get.translation(trigger.card),'需要额外使用一张','#y【闪】','响应'); - trigger.card.storage.mougong_logged=true; - } - var id=trigger.target.playerid; - var map=trigger.getParent().customArgs; - if(!map[id]) map[id]={}; - if(typeof map[id].shanRequired=='number'){ - map[id].shanRequired++; - } - else{ - map[id].shanRequired=2; - } - }, - ai:{ - directHit_ai:true, - skillTagFilter:function(player,tag,arg){ - if(arg.card.name!='sha'||(arg.card&&arg.card.storage&&!arg.card.storage.mougong_buffed)||(arg.target.countCards('h','shan')>=1&&!arg.target.storage.mougong_nuqi)) return false; - }, - }, - }, - shan:{ - trigger:{ - player:'shanEnd', - }, - forced:true, - silent:true, - popup:false, - charlotte:true, - filter:function(event,player){ - return event.getParent(3).name=='sha'&&event.getParent().card.storage&&event.getParent().card.storage.mougong_buffed&&_status.mougong_buff['shan'][1]=='double'; - }, - content:function(event,player){ - if(!trigger.card.storage.mougong_logged){ - game.log(player,'触发了强化闪的效果'); - game.log('#y'+get.translation(trigger.card),'视为两张','#y【闪】','的效果'); - trigger.card.storage.mougong_logged=true; - } - if(trigger.getParent(3).shanRequired) trigger.getParent(3).shanRequired--; - } - }, - damage:{ - trigger:{player:'damageBegin1'}, - forced:true, - silent:true, - popup:false, - charlotte:true, - filter:function(event,player){ - if(!event.card) return false; - var names=Object.keys(_status.mougong_buff),name=event.card.name; - return names.contains(name)&&event.getParent(2).player==event.source&&event.card.storage&&event.card.storage.mougong_buffed&&_status.mougong_buff[name][1]=='damage'; - }, - content:function(){ - if(!trigger.card.storage.mougong_logged){ - game.log(player,'触发了强化'+get.translation(trigger.card.name)+'的效果'); - game.log('#y'+get.translation(trigger.card),'造成的伤害','#y+1'); - trigger.card.storage.mougong_logged=true; - } - trigger.num++; - } - }, - tao:{ - trigger:{player:'useCard'}, - filter:function(event,player){ - return event.card.name=='tao'&&event.card.storage&&event.card.storage.mougong_buffed&&_status.mougong_buff['tao'][1]=='double'; - }, - forced:true, - silent:true, - popup:false, - charlotte:true, - content:function(){ - if(!trigger.card.storage.mougong_logged){ - game.log(player,'触发了强化桃的效果'); - game.log('#y'+get.translation(trigger.card),'的回复值','#y+1'); - trigger.card.storage.mougong_logged=true; - } - if(!trigger.baseDamage) trigger.baseDamage=1; - trigger.baseDamage++; - }, - } - } - }, - mougong_expose:{ + stratagem_expose:{ trigger:{player:'useCard'}, forced:true, silent:true, @@ -4087,7 +3891,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ filter:function(event,player){ if(event.targets[0]==player) return false; return event.targets.length==1&&event.targets[0]&&((player.storage.zhibi.contains(event.targets[0])||event.targets[0].identityShown) || - game.players.slice().concat(game.dead).filter(current=>(current.storage.mougong_showFan||current.storage.mougong_showZhu)&¤t.identityShown&¤t.storage.zhibi_for.contains(event.targets[0])).length); + game.players.slice().concat(game.dead).filter(current=>(current.storage.stratagem_show_fan||current.storage.stratagem_show_zhu)&¤t.identityShown&¤t.storage.zhibi_for.contains(event.targets[0])).length); }, content:function(){ if(!trigger.targets[0].storage.zhibi_for) trigger.targets[0].storage.zhibi_for=[]; @@ -4095,7 +3899,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } }, - mougong_shanAi:{ + stratagem_shan_ai:{ trigger:{ player:'chooseToUseBegin', }, @@ -4125,7 +3929,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ var target=_status.event.player; var evt=_status.event.getParent(2); var bool=true; - if(_status.event.getParent().shanRequired>1&&!get.is.object(card)&&(target.countCards('h','shan')<_status.event.getParent().shanRequired&&!(target.storage.mougong_nuqi>=1&&target.countCards('h','shan')==1&&_status.event.getParent().shanRequired<=2))){ + if(_status.event.getParent().shanRequired>1&&!get.is.object(card)&&(target.countCards('h','shan')<_status.event.getParent().shanRequired&&!(target.storage.stratagem_fury>=1&&target.countCards('h','shan')==1&&_status.event.getParent().shanRequired<=2))){ bool=false; } else if(target.hasSkillTag('useShan')){ @@ -4139,7 +3943,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }).set('shanRequired',evt.shanRequired); }, }, - mougong_cardEffect:{ + stratagem_card_effect:{ trigger:{ player:['useCard1'], }, @@ -4148,12 +3952,12 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ forced:true, charlotte:true, filter:function(event,player,name){ - return event.card&&event.card.storage&&event.card.storage.mougong_buffed&&event.cards.length; + return event.card&&event.card.storage&&event.card.storage.stratagemBuffed&&event.cards.length; }, content:function(){ game.broadcastAll(function(cards){ for(var i of cards){ - i.clone.classList.add('mougong_nuqi_glow'); + i.clone.classList.add('stratagem-fury-glow'); } },trigger.cards); } From 9e9283ecaf102327e146079a10e8ea63ddf6318f Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Thu, 19 Oct 2023 07:54:44 -0700 Subject: [PATCH 3/6] Make Kingdom War: Separatism online ready. --- game/game.js | 56 +++---- mode/brawl.js | 384 ----------------------------------------------- mode/guozhan.js | 36 +++-- mode/identity.js | 4 +- 4 files changed, 59 insertions(+), 421 deletions(-) diff --git a/game/game.js b/game/game.js index aa38dfbda..e6d60dc26 100644 --- a/game/game.js +++ b/game/game.js @@ -5589,6 +5589,9 @@ frequent:true, restart:true, }, + get connect_separatism(){ + return lib.mode.guozhan.config.separatism; + }, connect_initshow_draw:{ name:'首亮奖励', item:{ @@ -5679,6 +5682,13 @@ frequent:true, restart:true, }, + separatism:{ + name:'群雄割据', + init:false, + frequent:true, + restart:true, + intro:'开放不同势力组合,以优先亮出的武将牌作为自己的势力,双势力武将则使用列表的第一个势力' + }, initshow_draw:{ name:'首亮奖励', item:{ @@ -7258,11 +7268,6 @@ init:true, frequent:true }, - qunxionggeju:{ - name:'群雄割据', - init:true, - frequent:true - }, duzhansanguo:{ name:'毒战三国', init:true, @@ -7577,8 +7582,6 @@ }else if(newMessage.includes("has already been declared")){ messageName=newMessage.replace('SyntaxError: Identifier ', '').replace(' has already been declared', ''); newMessage=messageName +"变量已经被声明过,不能被重新声明"; - }else if(newMessage.includes("Invalid or unexpected token")){ - newMessage="查询无效或意外的标记,可能是字符串的引号不成对,错误使用了转义序列,字符串在多行中解析异常"; }else if(newMessage.includes("Duplicate parameter name not allowed in this context")) { newMessage="参数名不允许重复"; }else if(newMessage.includes("Unexpected reserved word")||newMessage.includes( @@ -11112,10 +11115,10 @@ } }, layout:function(layout,nosave){ - const previousTransitionDuration=document.body.style.transitionDuration; - document.body.style.transitionDuration='1s'; - const previousFilter=document.body.style.filter,previousWebkitFilter=document.body.style.webkitFilter; - document.body.style.filter=document.body.style.webkitFilter='brightness(0)'; + const previousTransitionDuration=document.documentElement.style.transitionDuration; + document.documentElement.style.transitionDuration='1s'; + const previousFilter=document.documentElement.style.filter,previousWebkitFilter=document.documentElement.style.webkitFilter; + document.documentElement.style.filter=document.documentElement.style.webkitFilter='brightness(0)'; if(layout=='default') layout='mobile'; if(!nosave) game.saveConfig('layout',layout); game.layout=layout; @@ -11226,14 +11229,14 @@ return new Promise(resolve=>setTimeout(resolve,500)); }).then(()=>{ ui.updatec(); - if(previousFilter) document.body.style.filter=previousFilter; - else document.body.style.removeProperty('filter'); - if(previousWebkitFilter) document.body.style.webkitFilter=previousWebkitFilter; - else document.body.style.removeProperty('-webkit-filter'); + if(previousFilter) document.documentElement.style.filter=previousFilter; + else document.documentElement.style.removeProperty('filter'); + if(previousWebkitFilter) document.documentElement.style.webkitFilter=previousWebkitFilter; + else document.documentElement.style.removeProperty('-webkit-filter'); return new Promise(resolve=>setTimeout(resolve,1000)); }).then(()=>{ - if(previousTransitionDuration) document.body.style.transitionDuration=previousTransitionDuration; - else document.body.style.removeProperty('transition-duration'); + if(previousTransitionDuration) document.documentElement.style.transitionDuration=previousTransitionDuration; + else document.documentElement.style.removeProperty('transition-duration'); }); }, background:function(){ @@ -42906,13 +42909,13 @@ player2.previousSeat=player.previousSeat; player2.nextSeat.previousSeat=player2; player2.previousSeat.nextSeat=player2; - const player3=player2.nextSeat; + let player3=player2.nextSeat; while(player3.isDead()){ player3=player3.nextSeat; } player3.previous=player2; player2.next=player3; - const player4=player2.previousSeat; + let player4=player2.previousSeat; while(player4.isDead()){ player4=player4.previousSeat; } @@ -52936,22 +52939,22 @@ //单个人物的宽度。这里要设置玩家的实际的宽度 const temporaryPlayer=ui.create.div('.player',ui.arena).hide(); const computedStyle=getComputedStyle(temporaryPlayer); - const scale=8/numberOfPlayers; + const scale=6/numberOfPlayers; //玩家顶部距离父容器上边缘的距离偏移的单位距离 - const oneThirdHeight=parseFloat(computedStyle.height)/3*scale; + const quarterHeight=parseFloat(computedStyle.height)/4*scale; const halfWidth=parseFloat(computedStyle.width)/2; temporaryPlayer.remove(); //列数,即假如8人场,除去自己后,上面7个人占7列 const columnCount=numberOfPlayers-1; - const percentage=100/numberOfPlayers; + const percentage=90/(columnCount-1); //仅当游戏人数大于8人,且玩家的座位号大于0时,设置玩家的位置。因为0号位是game.me在最下方,无需设置。 for(let ordinal=1;ordinal.player[data-position='${ordinal}']{`, - `left:calc(${percentage*(reversedOrdinal+1)}% - ${halfWidth}px);`, + `left:calc(${percentage*reversedOrdinal+5}% - ${halfWidth}px);`, `top:${top}px;`, `transform:scale(${scale});`, '}' @@ -58716,8 +58719,9 @@ default:return get.cnNumber(parseInt(config.number))+'人'+(config.double_character?'双将':'')+'身份'; } } - else if(config.mode=='guozhan'&&config.guozhan_mode!='normal'){ - switch(config.guozhan_mode){ + else if(config.mode=='guozhan'){ + if(config.separatism) return '群雄割据'; + if(config.guozhan_mode!='normal') switch(config.guozhan_mode){ case 'yingbian':return '应变国战'; case 'old':return '怀旧国战'; } diff --git a/mode/brawl.js b/mode/brawl.js index 020d2151b..8c80048b5 100644 --- a/mode/brawl.js +++ b/mode/brawl.js @@ -1143,377 +1143,6 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }, }, }, - qunxionggeju:{ - name:'群雄割据', - mode:'guozhan', - intro:[ - '开放不同势力组合,以优先亮出的武将牌作为自己的势力,双势力武将则使用列表的第一个势力', - ], - showcase:function(init){ - var node=this; - var list=[ - ['re_yuanshao','re_lidian'], - ['zhangliao','sunquan'], - ['xin_fazheng','sp_lvfan'], - ['sunjian','lvbu'], - ['jin_simashi','re_weiyan'], - ['guanyu','sunce'], - ['zhenji','sp_zhangjiao'], - ['guojia','sp_zhugeliang'], - ]; - list.randomSort(); - var func=function(){ - var card=ui.create.player(null,true); - var name=list.shift(); - card.init(name[0],name[1]); - card.node.marks.remove(); - card.node.count.remove(); - card.node.hp.remove(); - card.classList.remove('unseen'); - node.nodes.push(card); - card.style.position='absolute'; - card.style.zIndex=2; - card.style.transition='all 2s'; - var rand1=Math.round(Math.random()*100); - var rand2=Math.round(Math.random()*100); - var rand3=Math.round(Math.random()*40)-20; - card.style.left='calc('+rand1+'% - '+(rand1*1.5)+'px)'; - card.style.top='calc('+rand2+'% - '+(rand2*1.8)+'px)'; - card.style.transform='scale(0.8) rotate('+rand3+'deg)'; - node.appendChild(card); - ui.refresh(card); - }; - - var list2=['feilongduofeng','taipingyaoshu','dinglanyemingzhu']; - var func2=function(){ - var card=game.createCard(list2.shift(),'noclick'); - node.nodes.push(card); - card.style.position='absolute'; - card.style.zIndex=2; - card.style.transition='all 2s'; - var rand1=Math.round(Math.random()*100); - var rand2=Math.round(Math.random()*100); - var rand3=Math.round(Math.random()*40)-20; - card.style.left='calc('+rand1+'% - '+rand1+'px)'; - card.style.top='calc('+rand2+'% - '+rand2+'px)'; - card.style.transform='rotate('+rand3+'deg)'; - node.appendChild(card); - ui.refresh(card); - }; - if(init){ - node.nodes=[]; - } - else{ - while(node.nodes.length){ - node.nodes.shift().remove(); - } - } - for(var i=0;i<5;i++){ - func(); - } - for(var i=0;i<3;i++){ - func2(); - func(); - } - }, - init:function(){}, - content:{ - chooseCharacterBefore:function(){ - game.chooseCharacter=function(){ - var next=game.createEvent('chooseCharacter'); - next.showConfig=true; - next.addPlayer=true; - next.ai=function(player,list,back){ - var mainx=list[0]; - var vicex=list[1]; - if(get.guozhanReverse(mainx,vicex)){ - mainx=list[1]; - vicex=list[0]; - } - player.init(mainx,vicex,false); - if(back){ - list.remove(player.name1); - list.remove(player.name2); - for(var i=0;i'; - td.link=i-1; - seats.appendChild(td); - td.addEventListener(lib.config.touchscreen?'touchend':'click',function(){ - if(_status.dragged) return; - if(_status.justdragged) return; - if(_status.cheat_seat){ - _status.cheat_seat.classList.remove('bluebg'); - if(_status.cheat_seat==this){ - delete _status.cheat_seat; - return; - } - } - this.classList.add('bluebg'); - _status.cheat_seat=this; - }); - } - dialog.content.appendChild(seats); - if(game.me==game.zhu){ - seats.previousSibling.style.display='none'; - seats.style.display='none'; - } - - dialog.add(ui.create.div('.placeholder.add-setting')); - dialog.add(ui.create.div('.placeholder.add-setting')); - if(get.is.phoneLayout()) dialog.add(ui.create.div('.placeholder.add-setting')); - }; - var removeSetting=function(){ - var dialog=_status.event.dialog; - if(dialog){ - dialog.style.height=''; - delete dialog._scrollset; - var list=Array.from(dialog.querySelectorAll('.add-setting')); - while(list.length){ - list.shift().remove(); - } - ui.update(); - } - }; - event.addSetting=addSetting; - event.removeSetting=removeSetting; - - var chosen=lib.config.continue_name||[]; - game.saveConfig('continue_name'); - event.chosen=chosen; - - var i; - event.list=[]; - for(i in lib.character){ - if(i.indexOf('gz_shibing')==0) continue; - if(chosen.contains(i)) continue; - if(lib.filter.characterDisabled(i)) continue; - if(get.config('onlyguozhan')){ - if(!lib.characterPack.mode_guozhan[i]) continue; - if(get.is.jun(i)) continue; - } - if(lib.character[i][4].contains('hiddenSkill')) continue; - if(lib.character[i][2]==3||lib.character[i][2]==4||lib.character[i][2]==5) - event.list.push(i); - } - _status.characterlist=event.list.slice(0); - _status.yeidentity=[]; - event.list.randomSort(); - // var list=event.list.splice(0,parseInt(get.config('choice_num'))); - var list=event.list.randomRemove(parseInt(get.config('choice_num'))); - if(_status.auto){ - event.ai(game.me,list); - lib.init.onfree(); - } - else if(chosen.length){ - game.me.init(chosen[0],chosen[1],false); - lib.init.onfree(); - } - else{ - var dialog=ui.create.dialog('选择角色','hidden',[list,'character']); - if(get.config('change_identity')){ - addSetting(dialog); - } - var next=game.me.chooseButton(dialog,true,2).set('onfree',true); - next.filterButton=function(button){ - if(ui.dialog.buttons.length<=10){ - for(var i=0;i=8){ - addCharacter.disabled=true; - } return player; }; @@ -4711,12 +4333,6 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ line9.style.display='none'; line9.style.marginTop='20px'; var resetStatus=function(all){ - if(line7.childElementCount>=8){ - addCharacter.disabled=true; - } - else{ - addCharacter.disabled=false; - } // editCode.disabled=false; saveButton.disabled=false; // exportButton.disabled=false; diff --git a/mode/guozhan.js b/mode/guozhan.js index 5a91b83c3..ed0f15a64 100644 --- a/mode/guozhan.js +++ b/mode/guozhan.js @@ -99,11 +99,13 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(_status.brawl&&_status.brawl.submode){ _status.mode=_status.brawl.submode; } + if(get.config('separatism')) _status.separatism=true; } "step 1" if(_status.connectMode){ _status.mode=lib.configOL.guozhan_mode; if(!['normal','yingbian','old'].contains(_status.mode)) _status.mode='normal'; + if(lib.configOL.separatism) _status.separatism=true; //决定牌堆 switch(_status.mode){ case 'old':lib.card.list=lib.guozhanPile_old.slice(0);break; @@ -115,8 +117,9 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ default:lib.card.list=lib.guozhanPile.slice(0);break; } game.fixedPile=true; - game.broadcastAll(function(mode){ + game.broadcastAll((mode,separatism)=>{ _status.mode=mode; + if(separatism) _status.separatism=true; if(mode=='yingbian'){ delete lib.translate.shuiyanqijunx_info_guozhan; } @@ -145,7 +148,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } lib.characterReplace={}; - },_status.mode); + },_status.mode,_status.separatism); game.randomMapOL(); } else{ @@ -13504,6 +13507,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ else{ num={mark:'标记',draw:'摸牌'}[lib.configOL.initshow_draw]; } + uiintro.add('
    群雄割据:'+(lib.configOL.separatism?'开启':'关闭')); uiintro.add('
    首亮奖励:'+num); uiintro.add('
    珠联璧合:'+(lib.configOL.zhulian?'开启':'关闭')); uiintro.add('
    出牌时限:'+lib.configOL.choose_timeout+'秒'); @@ -13585,7 +13589,10 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }, getVideoName:function(){ var str=get.translation(game.me.name1)+'/'+get.translation(game.me.name2); - var str2=get.cnNumber(parseInt(get.config('player_number')))+'人'+ + var str2=_status.separatism?get.modetrans({ + mode:lib.config.mode, + separatism:true + }):get.cnNumber(parseInt(get.config('player_number')))+'人'+ get.translation(lib.config.mode); if(game.me.identity=='ye'){ str2+=' - 野心家'; @@ -13689,6 +13696,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } var filterChoice=function(name1,name2){ + if(_status.separatism) return true; var group1=lib.character[name1][1]; var group2=lib.character[name2][1]; var doublex=get.is.double(name1,true); @@ -13849,6 +13857,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } if(lib.character[button.link][4].contains('hiddenSkill')) return false; var filterChoice=function(name1,name2){ + if(_status.separatism) return true; var group1=lib.character[name1][1]; var group2=lib.character[name2][1]; var doublex=get.is.double(name1,true); @@ -14078,6 +14087,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } var filterChoice=function(name1,name2){ + if(_status.separatism) return true; var group1=lib.character[name1][1]; var group2=lib.character[name2][1]; var doublex=get.is.double(name1,true); @@ -14113,13 +14123,21 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ }).set('processAI',function(){ var buttons=_status.event.dialog.buttons; var filterChoice=function(name1,name2){ - if(get.is.double(name1)) return false; + if(_status.separatism) return true; var group1=lib.character[name1][1]; var group2=lib.character[name2][1]; - if(group1=='ye') return group2!='ye'; - var double=get.is.double(name2,true); - if(double) return double.contains(group1); - return group1==group2; + var doublex=get.is.double(name1,true); + if(doublex){ + var double=get.is.double(name2,true); + if(double) return doublex.some(group=>double.contains(group)); + return doublex.contains(group2); + } + else{ + if(group1=='ye') return group2!='ye'; + var double=get.is.double(name2,true); + if(double) return double.contains(group1); + return group1==group2; + } }; for(var i=0;i=Math.max(Math.round(get.totalPopulation()/2),3); + return game.roundNumber>=Math.max(Math.round(get.population()/2),3); } - if(event.name=='die') return game.dead.length>=Math.max(Math.round(get.totalPopulation()/3),2); + if(event.name=='die') return game.dead.length>=Math.max(Math.round(get.population()/3),2); } return false; }, From 661813cdc819e5aba60ea7d459a63c6ab7f82f07 Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Mon, 23 Oct 2023 06:46:29 -0700 Subject: [PATCH 4/6] Add the handler mechanic, property operation methods, and greatly optimize stratagem mode. --- card/standard.js | 2 +- game/game.js | 716 ++++++++++++++++++++++++-------------- layout/default/layout.css | 25 +- mode/doudizhu.js | 4 +- mode/identity.js | 511 +++++++++++---------------- 5 files changed, 686 insertions(+), 572 deletions(-) diff --git a/card/standard.js b/card/standard.js index cf6f1e2a2..2454de7c2 100644 --- a/card/standard.js +++ b/card/standard.js @@ -141,7 +141,7 @@ game.import('card',function(lib,game,ui,get,ai,_status){ var target=_status.event.player; var evt=_status.event.getParent(); var bool=true; - if(_status.event.shanRequired>1&&!get.is.object(card)&&target.countCards('h','shan')<_status.event.shanRequired){ + if(_status.event.shanRequired>1&&!get.is.object(card)&&target.countCards('h','shan')<_status.event.shanRequired-(_status.event.shanIgnored||0)){ bool=false; } else if(target.hasSkillTag('useShan')){ diff --git a/game/game.js b/game/game.js index e6d60dc26..93122aa72 100644 --- a/game/game.js +++ b/game/game.js @@ -4,7 +4,7 @@ * @typedef {InstanceType} Player * @typedef {InstanceType} Card * @typedef {InstanceType} VCard - * @typedef {InstanceType} GameEvent + * @typedef {InstanceType} GameEvent * @typedef {InstanceType} NodeWS */ const userAgent=navigator.userAgent.toLowerCase(); @@ -614,19 +614,82 @@ * 谋攻强化 */ stratagemBuff:{ - buff:new Map([ - ['sha',[1,'require']], - ['shan',[1,'double']], - ['juedou',[2,'damage']], - ['huogong',[2,'damage']], - ['tao',[3,'double']] + cost:new Map([ + ['sha',1], + ['shan',1], + ['juedou',2], + ['huogong',2], + ['tao',3] + ]), + effect:new Map([ + ['sha',event=>{ + if(event.step!=1) return; + game.log(event.player,'触发了强化效果'); + game.log(event.card,'抵消所需要的',`#y【${get.translation('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=>{ + if(event.step!=1) return; + game.log(event.player,'触发了强化效果'); + game.log(event.card,'视为两张',`#y【${get.translation('shan')}】`,'的效果'); + event.getParent(2).decrease('shanRequired',1); + }], + ['juedou',event=>{ + if(event.step!=1) 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=>{ + if(event.step!=1) return; + game.log(event.player,'触发了强化效果'); + game.log(event.card,'造成的伤害+1'); + event.increase('baseDamage',1); + }], + ['tao',event=>{ + if(event.step!=1) return; + game.log(event.player,'触发了强化效果'); + game.log(event.card,'回复的体力+1'); + event.increase('baseDamage',1); + }] ]), prompt:new Map([ - ['sha','响应时所需【闪】数+1。'], - ['shan','视为两张【闪】的效果。'], - ['juedou','对目标造成的伤害+1。'], - ['huogong','造成的伤害+1。'], - ['tao','回复值+1。'] + [ + 'sha', + /** + * @type {() => string} + */ + ()=>`抵消所需要的【${get.translation('shan')}】数+1。` + ], + [ + 'shan', + /** + * @type {() => string} + */ + ()=>`使用时视为两张【${get.translation('shan')}】的效果。` + ], + [ + 'juedou', + ()=>'对此牌的目标造成伤害时,伤害+1。' + ], + [ + 'huogong', + ()=>'造成的伤害+1。' + ], + [ + 'tao', + ()=>'回复的体力+1。' + ] ]) }, /** @@ -8261,7 +8324,7 @@ lib.ui=ui; lib.ai=ai; lib.game=game; - _status.event=new lib.element.Event().finish(); + _status.event=lib.element.GameEvent.initialGameEvent(); HTMLDivElement.prototype.animate=function(name,time){ var that; @@ -12333,6 +12396,7 @@ cooperation_use_info:'双方累计使用至少4种花色的牌', charge:'蓄力值', expandedSlots:'扩展装备栏', + stratagem_fury:'怒气', _stratagem_add_buff:'强化' }, element:{ @@ -20644,6 +20708,17 @@ } } //新函数 + changeFury(amount,limit){ + if(typeof this.storage.stratagem_fury!='number') this.storage.stratagem_fury=0; + if(!amount) return; + const furyBefore=this.storage.stratagem_fury; + if(limit===true&&typeof _status.stratagemFuryMax=='number') this.storage.stratagem_fury=Math.min(Math.max(furyBefore+amount,0),_status.stratagemFuryMax); + else this.storage.stratagem_fury=Math.max(furyBefore+amount,0); + const difference=this.storage.stratagem_fury-furyBefore; + if(!difference) return; + game.log(this,difference>0?'获得了':'失去了',get.cnNumber(Math.abs(difference)),'点','#r怒气'); + this.markSkill('stratagem_fury'); + } /** * version 1.4 * @@ -30348,11 +30423,15 @@ return this; } copy(){ + /** + * @type {Card} + */ var node=this.cloneNode(true); node.style.transform=''; node.name=this.name; node.suit=this.suit; node.number=this.number; + node.nature=this.nature; node.classList.remove('hidden'); node.classList.remove('start'); node.classList.remove('thrown'); @@ -30467,14 +30546,14 @@ if(typeof autoViewAs=='string') this.name=autoViewAs; } } - else if(typeof suitOrCard!='string'){ + else if(suitOrCard&&typeof suitOrCard!='string'){ Object.keys(suitOrCard).forEach(key=>{ const propertyDescriptor=Object.getOwnPropertyDescriptor(suitOrCard,key),value=propertyDescriptor.value; if(Array.isArray(value)) this[key]=value.slice(); else Object.defineProperty(this,key,propertyDescriptor); }); if(Array.isArray(numberOrCards)){ - const noCards=!this.hasOwnProperty('cards'); + const noCards=!('cards' in this); /** * @type {Card[]} */ @@ -30482,8 +30561,8 @@ 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(!this.hasOwnProperty('number')) this.number=get.number(this); - if(!this.hasOwnProperty('nature')) this.nature=get.nature(this); + if(!('number' in this)) this.number=get.number(this); + if(!('nature' in this)) this.nature=get.nature(this); } } const info=get.info(this,false); @@ -30496,9 +30575,9 @@ if(typeof numberOrCards=='number') this.number=numberOrCards; if(typeof name=='string') this.name=name; if(typeof nature=='string') this.nature=nature; - if(this.hasOwnProperty('suit')&&!this.hasOwnProperty('color')) this.color=get.color(this); - if(!this.hasOwnProperty('storage')) this.storage={}; - if(!this.hasOwnProperty('cards')) this.cards=[]; + if('suit' in this&&!('color' in this)) this.color=get.color(this); + if(!('storage' in this)) this.storage={}; + if(!('cards' in this)) this.cards=[]; } sameSuitAs(card){ return get.suit(this)==get.suit(card); @@ -30555,21 +30634,28 @@ _status.event.excludeButton.add(this); } }, - Event:class{ + GameEvent:class{ /** * @param {string} [name] * @param {false} [trigger] */ constructor(name,trigger){ - this.name=name; + if(typeof name=='string'){ + this.name=name; + const gameEvent=get.event(); + if(gameEvent){ + const type=`onNext${name[0].toUpperCase()}${name.slice(1)}`; + if(gameEvent.hasHandler(type)) this.pushHandler(...gameEvent.getHandler(type)); + } + } this.step=0; this.finished=false; /** - * @type {this[]} + * @type {GameEvent[]} */ this.next=[]; /** - * @type {this[]} + * @type {GameEvent[]} */ this.after=[]; this.custom={ @@ -30582,6 +30668,105 @@ this._set=[]; if(trigger!==false&&!game.online) this._triggered=0; } + static initialGameEvent(){ + return new lib.element.GameEvent().finish(); + } + /** + * @param {keyof this} key + * @param {number} [value] + * @param {number} [baseValue] + */ + addNumber(key,value,baseValue){ + if(typeof value!='number') value=0; + if(typeof this[key]=='number') this[key]+=value; + else{ + if(typeof baseValue!='number') baseValue=0; + this[key]=baseValue+value; + } + return this; + } + /** + * @param {keyof this} key + * @param {number} [baseValue] + */ + decrease(key,baseValue){ + if(typeof this[key]=='number') this[key]--; + else this.subtractNumber(key,1,baseValue); + return this; + } + /** + * @param {keyof this} key + * @param {number} [baseValue] + */ + increase(key,baseValue){ + if(typeof this[key]=='number') this[key]++; + else this.addNumber(key,1,baseValue); + return this; + } + /** + * @param {keyof this} key + * @param {number} [value] + * @param {number} [baseValue] + */ + subtractNumber(key,value,baseValue){ + if(typeof value!='number') value=0; + if(typeof this[key]=='number') this[key]-=value; + else{ + if(typeof baseValue!='number') baseValue=0; + this[key]=baseValue-value; + } + return this; + } + /** + * @param {Parameters[0]} [type] + * @param {GameEvent} [event] + * @returns {this} + */ + callHandler(type,event){ + if(this.hasHandler(type)){ + if(!event) event=this; + this.getHandler(type).forEach(handler=>{ + if(typeof handler=='function') handler(event); + }); + } + return this; + } + getDefaultHandlerType(){ + const eventName=this.name; + if(eventName) return `on${eventName[0].toUpperCase()}${eventName.slice(1)}`; + } + /** + * @param {Parameters[0]} [type] + * @returns {((event: GameEvent) => void)[]} + */ + getHandler(type){ + if(!type) type=this.getDefaultHandlerType(); + const currentHandler=this[type]; + if(!currentHandler) this[type]=[]; + else if(!Array.isArray(currentHandler)) this[type]=[currentHandler]; + return this[type]; + } + /** + * @param {`on${Capitalize}`} [type] + */ + hasHandler(type){ + if(!type) type=this.getDefaultHandlerType(); + return Boolean(this[type]&&this.getHandler(type).length); + } + /** + * @overload + * @param {...((event: GameEvent) => void)[]} handlers + * @returns {number} + */ + /** + * @overload + * @param {Parameters[0]} type + * @param {...((event: GameEvent) => void)[]} handlers + * @returns {number} + */ + pushHandler(type){ + return typeof type=='string'?this.getHandler(type).push(...Array.from(arguments).slice(1)):this.getHandler().push(...arguments); + } changeToZero(){ this.num=0; this.numFixed=true; @@ -30796,14 +30981,14 @@ return this._rand; } insert(content,map){ - const next=new lib.element.Event(`${this.name}Inserted`,false); + const next=new lib.element.GameEvent(`${this.name}Inserted`,false); this.next.push(next); next.setContent(content); Object.entries(map).forEach(entry=>next.set(entry[0],entry[1])); return next; } insertAfter(content,map){ - const next=new lib.element.Event(`${this.name}Inserted`,false); + const next=new lib.element.GameEvent(`${this.name}Inserted`,false); this.after.push(next); next.setContent(content); Object.entries(map).forEach(entry=>next.set(entry[0],entry[1])); @@ -31313,6 +31498,56 @@ } return this; } + /** + * @throws {'Do not call this method'} + */ + typeAnnotation(){ + /** + * @type {Player} + */ + this.source; + /** + * @type {Player} + */ + this.player; + /** + * @type {Player} + */ + this.target; + /** + * @type {Player[]} + */ + this.targets; + /** + * @type {Card} + */ + this.card; + /** + * @type {Card[]} + */ + this.cards; + /** + * @type {string} + */ + this.skill; + /** + * @type {boolean} + */ + this.forced; + /** + * @type {number} + */ + this.num; + /** + * @type {GameEvent} + */ + this._trigger; + /** + * @type {Record} + */ + this._result; + throw 'Do not call this method'; + } }, Dialog:class extends HTMLDivElement{ constructor(){ @@ -31760,10 +31995,10 @@ return this.Button.prototype; }, /** - * @legacy Use {@link lib.element.Event.prototype} instead. + * @legacy Use {@link lib.element.GameEvent.prototype} instead. */ get event(){ - return this.Event.prototype; + return this.GameEvent.prototype; }, /** * @legacy Use {@link lib.element.Dialog.prototype} instead. @@ -32467,214 +32702,140 @@ } }, skill:{ + stratagem_fury:{ + marktext:'🔥', + intro:{ + name:'怒气', + content:(storage,player)=>{ + const stratagemFuryMax=_status.stratagemFuryMax,fury=storage||0; + return `当前怒气值:${typeof stratagemFuryMax=='number'?`${fury}/${stratagemFuryMax}`:fury}`; + } + } + }, _stratagem_add_buff:{ + log:false, enable:'chooseToUse', - filter:function(event,player){ - if(!event.stratagemSettings) return false; - if(game.roundNumber<2&&!event.stratagemSettings.roundOneUseFury) return false; - var cards=player.getCards('hs'); - var names=Array.from(lib.stratagemBuff.buff.keys()); + filter:(event,player)=>{ + const fury=player.storage.stratagem_fury; + if(!fury) return false; + const stratagemSettings=event.stratagemSettings; + if(!stratagemSettings||!stratagemSettings.roundOneUseFury&&game.roundNumber<2) return false; + const cards=player.getCards('hs'); + if(!cards.length) return false; + const cost=lib.stratagemBuff.cost,names=Array.from(cost.keys()); if(!names.length) return false; - for(var card of cards){ - if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; - for(var name of names){ - var myName=get.name(card,player),nature=get.nature(card,player); - if(name==myName){ - if(event.filterCard({name:name,nature:nature,isCard:true,cards:[card]},player,event)){ - if(player.storage.stratagem_fury>=lib.stratagemBuff.buff.get(name)[0]) - return true; - } - } - } - } - return false; + return cards.some(card=>game.checkMod(card,player,'unchanged','cardEnabled2',player)&&names.some(availableName=>availableName==get.name(card,player)&&event.filterCard(new lib.element.VCard({ + name:availableName, + nature:get.nature(card,player), + isCard:true, + cards:[card] + }),player,event)&&fury>=cost.get(availableName))); }, - onChooseToUse:function(event){ - if(!event.stratagemSettings&&!game.online){ - event.set('stratagemSettings',{ - roundOneUseFury:_status.connectMode?lib.configOL.round_one_use_fury:get.config('round_one_use_fury') - }); - } + onChooseToUse:event=>{ + const player=_status.event.player,fury=player.storage.stratagem_fury; + if(!fury) return; + if(!event.stratagemSettings&&!game.online) event.set('stratagemSettings',{ + roundOneUseFury:_status.connectMode?lib.configOL.round_one_use_fury:get.config('round_one_use_fury') + }); + const cost=lib.stratagemBuff.cost.get('shan'); + if(typeof cost!='number'||!event.shanRequired) return; + event.addNumber('shanIgnored',Math.min(player.countCards(lib.skill._stratagem_add_buff.position,{ + name:'shan' + }),Math.floor(fury/cost))); }, - check:function(card){ - var player=_status.event.player; + check:card=>{ + const player=_status.event.player; if(_status.event.type=='phase'){ - var name=get.name(card,player); - if(name=='sha'){ + const cardName=get.name(card,player); + if(cardName=='sha'){ if(game.hasPlayer(current=>{ - return player.canUse(card,current)&&(player.storage.zhibi&&!player.storage.zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(player.storage.stratagem_fury||0)-1)))&¤t.mayHaveShan()&&player.hasSkill('jiu'); + if(!player.canUse(card,current)) return false; + const storage=player.storage,zhibi=storage.zhibi; + return (zhibi&&!zhibi.includes(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(storage.stratagem_fury||0)-1)))&¤t.mayHaveShan()&&player.hasSkill('jiu'); })) return 1; return 0; - } else if(name=='tao'){ + } + if(cardName=='tao'){ if(player.hp<=2&&player.getDamagedHp()>=2) return 1; return 0; } return 1; } - else if(_status.event.type=='dying') return get.attitude(player,_status.event.dying)>3?1:0; + if(_status.event.type=='dying') return get.attitude(player,_status.event.dying)>3?1:0; return (_status.event.getParent().shanRequired||1)>1&&get.damageEffect(player,_status.event.getParent().player||player,player)<0?1:0; }, position:'hs', - filterCard:function(card,player,event){ - event=event||_status.event; - var filter=event._backup.filterCard; - var names=Array.from(lib.stratagemBuff.buff.keys()); - for(var name of names){ - var myName=get.name(card,player),nature=get.nature(card,player); - if(name==myName){ - if(filter({name:name,nature:nature,isCard:true,cards:[card]},player,_status.event)){ - if(player.storage.stratagem_fury>=lib.stratagemBuff.buff.get(name)[0]){ - return true; - } - } - } - } - return false; + filterCard:(card,player,event)=>{ + if(!event) event=_status.event; + const filterCard=event._backup.filterCard; + const cost=lib.stratagemBuff.cost; + return Array.from(cost.keys()).some(availableName=>availableName==get.name(card,player)&&filterCard(new lib.element.VCard({ + name:availableName, + nature:get.nature(card,player), + isCard:true, + cards:[card] + }),player,_status.event)&&player.storage.stratagem_fury>=cost.get(availableName)); }, - viewAs:function(cards,player){ - var name=get.name(cards[0],player); - var nature=get.nature(cards[0],player); - if(name){ - return { - name:name, - nature:nature, - suit:get.suit(cards[0],player), - number:get.number(cards[0],player), - isCard:true, - cards:[cards[0]], - storage:{stratagemBuffed:1}, - }; - } - return null; + viewAs:(cards,player)=>{ + const cardName=get.name(cards[0],player); + return cardName?new lib.element.VCard({ + name:cardName, + nature:get.nature(cards[0],player), + suit:get.suit(cards[0],player), + number:get.number(cards[0],player), + isCard:true, + cards:[cards[0]], + storage:{ + stratagem_buffed:1 + } + }):new lib.element.VCard(); }, prompt:()=>{ const span=document.createElement('span'); span.classList.add('text'); span.style.fontFamily='yuanli'; - const stratagemBuff=lib.stratagemBuff,buff=stratagemBuff.buff; + const stratagemBuff=lib.stratagemBuff,cost=stratagemBuff.cost; stratagemBuff.prompt.forEach((prompt,cardName)=>{ const li=document.createElement('li'); - li.innerHTML=`【${get.translation(cardName)}】:${buff.get(cardName)[0]}点怒气。${prompt}`; + li.innerHTML=`【${get.translation(cardName)}】:${cost.get(cardName)}点怒气。${prompt()}`; span.appendChild(li); }); return `当你需要使用位于“强化表”内的非虚拟卡牌时,你可以消耗对应数量的怒气将其强化并使用。${document.createElement('hr').outerHTML}${span.outerHTML}`; }, - precontent:function(){ - 'step 0' - player.changeFury(-lib.stratagemBuff.buff.get(event.result.card.name)[0]); + onuse:(result,player)=>{ + player.logSkill(result.skill); + const stratagemBuff=lib.stratagemBuff,cardName=result.card.name; + player.changeFury(-stratagemBuff.cost.get(cardName),true); + const gameEvent=get.event(),effect=stratagemBuff.effect.get(cardName); + if(typeof effect=='function') gameEvent.pushHandler('onNextUseCard',effect); + gameEvent.pushHandler('onNextUseCard',event=>{ + if(event.step==1) game.broadcastAll(cards=>cards.forEach(card=>card.clone.classList.add('stratagem-fury-glow')),event.cards); + }); }, ai:{ - order:function(item,player){ - var player=player||_status.event.player; - if(_status.event.type=='phase'){ - var cards=player.getCards('hs'); - for(var card of cards){ - if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; - var name=get.name(card,player); - if(name=='sha'){ - if(game.hasPlayer(current=>{ - return player.canUse(card,current)&&(player.storage.zhibi&&!player.storage.zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(player.storage.stratagem_fury||0)-1)))&¤t.mayHaveShan(); - })) return get.order(card,player)+0.5; - } else if(name=='tao'){ - if(player.hp<=2&&player.getDamagedHp()>=2) return get.order(card,player)+0.5; - } - return 8; + order:(item,player)=>{ + if(!player) player=_status.event.player; + if(_status.event.type=='phase') for(const card of player.getCards('hs')){ + if(!game.checkMod(card,player,'unchanged','cardEnabled2',player)) continue; + const cardName=get.name(card,player); + if(cardName=='sha'){ + if(game.hasPlayer(current=>{ + if(!player.canUse(card,current)) return false; + const storage=player.storage,zhibi=storage.zhibi; + return (zhibi&&!zhibi.contains(current)||(get.effect(current,card,player,player)>=2-Math.max(0,(storage.stratagem_fury||0)-1)))&¤t.mayHaveShan(); + })) return get.order(card,player)+0.5; } + else if(cardName=='tao'&&player.hp<=2&&player.getDamagedHp()>=2) return get.order(card,player)+0.5; + return 8; } return 3.5; }, - }, - subSkill:{ - sha:{ - trigger:{player:'useCardToPlayered'}, - forced:true, - silent:true, - popup:false, - charlotte:true, - filter:function(event,player){ - return event.card.name=='sha'&&event.card.storage&&event.card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get('sha')[1]=='require'&&!event.getParent().directHit.contains(event.target); - }, - content:function(){ - if(!trigger.card.storage.stratagem_logged){ - game.log(player,'触发了强化杀的效果'); - game.log('#y'+get.translation(trigger.card),'需要额外使用一张','#y【闪】','响应'); - trigger.card.storage.stratagem_logged=true; - } - var id=trigger.target.playerid; - var map=trigger.getParent().customArgs; - if(!map[id]) map[id]={}; - if(typeof map[id].shanRequired=='number'){ - map[id].shanRequired++; - } - else{ - map[id].shanRequired=2; - } - }, - ai:{ - directHit_ai:true, - skillTagFilter:function(player,tag,arg){ - if(arg.card.name!='sha'||(arg.card&&arg.card.storage&&!arg.card.storage.stratagemBuffed)||(arg.target.countCards('h','shan')>=1&&!arg.target.storage.stratagem_fury)) return false; - }, - }, - }, - shan:{ - trigger:{ - player:'shanEnd', - }, - forced:true, - silent:true, - popup:false, - charlotte:true, - filter:function(event,player){ - return event.getParent(3).name=='sha'&&event.getParent().card.storage&&event.getParent().card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get('shan')[1]=='double'; - }, - content:function(event,player){ - if(!trigger.card.storage.stratagem_logged){ - game.log(player,'触发了强化闪的效果'); - game.log('#y'+get.translation(trigger.card),'视为两张','#y【闪】','的效果'); - trigger.card.storage.stratagem_logged=true; - } - if(trigger.getParent(3).shanRequired) trigger.getParent(3).shanRequired--; - } - }, - damage:{ - trigger:{player:'damageBegin1'}, - forced:true, - silent:true, - popup:false, - charlotte:true, - filter:function(event,player){ - if(!event.card) return false; - var names=Array.from(lib.stratagemBuff.buff.keys()),name=event.card.name; - return names.contains(name)&&event.getParent(2).player==event.source&&event.card.storage&&event.card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get(name)[1]=='damage'; - }, - content:function(){ - if(!trigger.card.storage.stratagem_logged){ - game.log(player,'触发了强化'+get.translation(trigger.card.name)+'的效果'); - game.log('#y'+get.translation(trigger.card),'造成的伤害','#y+1'); - trigger.card.storage.stratagem_logged=true; - } - trigger.num++; - } - }, - tao:{ - trigger:{player:'useCard'}, - filter:function(event,player){ - return event.card.name=='tao'&&event.card.storage&&event.card.storage.stratagemBuffed&&lib.stratagemBuff.buff.get('tao')[1]=='double'; - }, - forced:true, - silent:true, - popup:false, - charlotte:true, - content:function(){ - if(!trigger.card.storage.stratagem_logged){ - game.log(player,'触发了强化桃的效果'); - game.log('#y'+get.translation(trigger.card),'的回复值','#y+1'); - trigger.card.storage.stratagem_logged=true; - } - if(!trigger.baseDamage) trigger.baseDamage=1; - trigger.baseDamage++; - }, + directHit_ai:true, + skillTagFilter:(player,tag,arg)=>{ + const card=arg.card; + if(card.name!='sha'||!card.storage.stratagem_buffed) return false; + const target=arg.target; + if(target.countCards('h','shan')>=1&&!target.storage.stratagem_fury) return false; } } }, @@ -34540,11 +34701,7 @@ lib.characterPack[i]=mode.characterPack[i]; } } - _status.event={ - finished:true, - next:[], - after:[] - }; + _status.event=lib.element.GameEvent.initialGameEvent(); _status.paused=false; game.createEvent('game',false).setContent(lib.init.startOnline); game.loop(); @@ -34805,11 +34962,7 @@ game.arrangePlayers(); ui.create.me(true); - _status.event={ - finished:true, - next:[], - after:[] - }; + _status.event=lib.element.GameEvent.initialGameEvent(); _status.paused=false; _status.dying=get.parsedResult(state.dying)||[]; @@ -35353,6 +35506,11 @@ } }; const game={ + //Stratagem + //谋攻 + setStratagemBuffCost:(cardName,cost)=>game.broadcastAll((clientCardName,clientCost)=>lib.stratagemBuff.cost.set(clientCardName,clientCost),cardName,cost), + setStratagemBuffEffect:(cardName,effect)=>game.broadcastAll((clientCardName,clientEffect)=>lib.stratagemBuff.cost.set(clientCardName,clientEffect),cardName,effect), + setStratagemBuffPrompt:(cardName,prompt)=>game.broadcastAll((clientCardName,clientPrompt)=>lib.stratagemBuff.cost.set(clientCardName,clientPrompt),cardName,prompt), //添加新的属性杀 addNature:(nature,translation,config)=>{ if(!nature) throw new TypeError(); @@ -36100,6 +36258,7 @@ delete parsedPath.base; if(!parsedPath.dir) parsedPath.dir='image/card/'; if(!parsedPath.ext) parsedPath.ext='.jpg'; + const fileName=parsedPath.name; game.broadcastAll((formattedPath,name,skill,player)=>{ const node=ui.create.div('.background.upper.land'); node.setBackgroundImage(formattedPath); @@ -36138,7 +36297,7 @@ return uiIntro; },200); game.addGlobalSkill(skill); - },lib.path.format(parsedPath),parsedPath.name,`${name}_skill`,player); + },lib.path.format(parsedPath),fileName,`${fileName}_skill`,player); }, checkFileList:function(updates,proceed){ var n=updates.length; @@ -36305,6 +36464,12 @@ delete ui.currentpopped; } }, + /** + * @type {{ + * (func: T, ...args: Parameters) => void; + * (func: (...args: T) => void, ...args: T) => void; + * }} + */ broadcast:function(){ if(!lib.node||!lib.node.clients||game.online) return; for(var i=0;i(func: T, ...args: Parameters) => void; + * (func: (...args: T) => void, ...args: T) => void; + * }} + */ broadcastAll:function(){ if(game.online) return; var argc=arguments.length; @@ -39270,10 +39441,10 @@ next.setContent('createTrigger'); }, /** - * @legacy Use {@link lib.element.Event.constructor} instead. + * @legacy Use {@link lib.element.GameEvent.constructor} instead. */ createEvent:(name,trigger,triggerEvent)=>{ - const next=new lib.element.Event(name,trigger); + const next=new lib.element.GameEvent(name,trigger); (triggerEvent||_status.event).next.push(next); return next; }, @@ -40388,6 +40559,7 @@ }*/ } else{ + event.callHandler(); if(player&&player.classList.contains('dead')&&!event.forceDie&&event.name!='phaseLoop'){ game.broadcastAll(function(){ while(_status.dieClose.length){ @@ -40483,6 +40655,7 @@ } event.clearStepCache(); event.step++; + if(event.finished) event.callHandler(); } } } @@ -41318,11 +41491,7 @@ // lib.config.addedpile=pilecfg[1]||{}; // } - _status.event={ - finished:true, - next:[], - after:[] - }; + _status.event=lib.element.GameEvent.initialGameEvent(); _status.paused=false; if(_status.connectMode&&lib.mode[name].connect){ @@ -42280,9 +42449,10 @@ log:function(){ let str='',str2='',logvid=null; const color=new Map([ - ['b','blue'], + ['r','fire'], ['y','yellow'], - ['g','green'] + ['g','green'], + ['b','blue'] ]); Array.from(arguments).forEach(value=>{ const itemtype=get.itemtype(value); @@ -55940,49 +56110,52 @@ } } }, - ok:function(node){ - var event=_status.event; - if(event.custom&&event.custom.replace.confirm){ - event.custom.replace.confirm(true);return; + ok:node=>{ + const gameEvent=get.event(),custom=gameEvent.custom,replaceConfirm=custom.replace.confirm; + if(replaceConfirm){ + replaceConfirm(true); + return; } - event.result={ - buttons:ui.selected.buttons.slice(0), - cards:ui.selected.cards.slice(0), - targets:ui.selected.targets.slice(0), + const result=gameEvent.result={ + buttons:ui.selected.buttons.slice(), + cards:ui.selected.cards.slice(), + targets:ui.selected.targets.slice(), confirm:'ok', bool:true, links:get.links(ui.selected.buttons) }; - if(node){ - node.parentNode.close(); - } - if(event.skill){ - event.result.skill=event.skill; - if(typeof get.info(event.skill).viewAs=='function') event.result.card=get.info(event.skill).viewAs(event.result.cards,event.player); - else event.result.card=get.copy(get.info(event.skill).viewAs); - if(event.result.cards.length==1&&event.result.card){ - if(!event.result.card.suit) event.result.card.suit=get.suit(event.result.cards[0]); - if(!event.result.card.number) event.result.card.number=get.number(event.result.cards[0]); + if(node) node.parentNode.close(); + const skill=gameEvent.skill; + if(skill){ + result.skill=skill; + const skillInformation=get.info(gameEvent.skill),viewAs=skillInformation.viewAs; + if(typeof viewAs=='function'){ + const viewedAs=viewAs(result.cards,gameEvent.player); + if(viewedAs){ + viewedAs.cards=result.cards; + result.card=get.autoViewAs(viewedAs); + } } - if(event.skillDialog&&get.objtype(event.skillDialog)=='div'){ - event.skillDialog.close(); + else if(viewAs){ + viewAs.cards=result.cards; + result.card=get.autoViewAs(viewAs); } - var cards=event.player.getCards('hej'); + if(gameEvent.skillDialog&&get.objtype(gameEvent.skillDialog)=='div'){ + gameEvent.skillDialog.close(); + } + var cards=gameEvent.player.getCards('hej'); for(var i=0;i{ + const modeConfig=lib.config.mode_config; + if(modeConfig){ + const identityConfig=modeConfig.identity; + if(identityConfig){ + const identityLists=identityConfig.identity; + if(identityLists){ + const identityList=identityLists[numberOfPlayers-2]; + if(Array.isArray(identityList)) return identityList.slice(); + } + } + } + const numberOfPlayersExceptLord=numberOfPlayers-1,numberOfLoyalists=Math.round(numberOfPlayersExceptLord*3/9),numberOfSpys=Math.round(numberOfPlayersExceptLord*2/9); + return ['zhu'].concat(Array.from({ + length:numberOfLoyalists + },()=>'zhong'),Array.from({ + length:numberOfSpys + },()=>'nei'),Array.from({ + length:numberOfPlayersExceptLord-numberOfLoyalists-numberOfSpys + },()=>'fan')); + }, //Generate an object URL from the Base64-encoded octet stream //从Base64编码的八位字节流生成对象URL objectURL:octetStream=>{ @@ -59096,14 +59294,14 @@ if(key=='_trigger'){ if(noMore!==false) stringifying[key]=get.eventInfoOL(entry[1],null,false); } - else if(!lib.element.Event.prototype[key]&&key!='content'&&get.itemtype(entry[1])!='event') stringifying[key]=get.stringifiedResult(entry[1],null,false); + else if(!lib.element.GameEvent.prototype[key]&&key!='content'&&get.itemtype(entry[1])!='event') stringifying[key]=get.stringifiedResult(entry[1],null,false); return stringifying; },{}))}`:'', /** * @param {string} item */ infoEventOL:item=>{ - const evt=new lib.element.Event(); + const evt=new lib.element.GameEvent(); try{ Object.entries(JSON.parse(item.slice(14))).forEach(entry=>{ const key=entry[0]; @@ -59336,7 +59534,7 @@ if(obj.classList.contains('dialog')) return 'dialog'; } if(get.is.object(obj)){ - if(obj.isMine==lib.element.Event.prototype.isMine) return 'event'; + if(obj.isMine==lib.element.GameEvent.prototype.isMine) return 'event'; } }, equipNum:card=>{ @@ -59647,6 +59845,13 @@ } return card; }, + /** + * @template T + * @type {{ + * (key: T) => GameEvent[T]; + * () => GameEvent; + * }} + */ event:key=>key?_status.event[key]:_status.event, player:()=>_status.event.player, players:(sort,dead,out)=>{ @@ -59720,6 +59925,9 @@ // replace(/阵法技/g,'阵法技'). // replace(/主公技/g,'主公技'); }, + /** + * @returns {string} + */ translation:(str,arg)=>{ if(str&&typeof str=='object'&&(str.name||str._tempTranslate)){ if(str._tempTranslate) return str._tempTranslate; @@ -61722,6 +61930,7 @@ var event=_status.event; var eventskill=null; if(player==undefined) player=_status.event.player; + if(typeof card=='object') card=get.autoViewAs(card); if(typeof card!='string'&&(typeof card!='object'||!card.name)){ var skillinfo=get.info(event.skill); if(event.skill&&skillinfo.viewAs==undefined) card=_status.event.skill; @@ -61916,6 +62125,7 @@ var event=_status.event; var eventskill=null; if(player==undefined) player=_status.event.player; + if(typeof card=='object') card=get.autoViewAs(card); if(typeof card!='string'&&(typeof card!='object'||!card.name)){ var skillinfo=get.info(event.skill); if(event.skill&&skillinfo.viewAs==undefined) card=_status.event.skill; @@ -62356,7 +62566,7 @@ Object.defineProperty(cardPrototype,key,Object.getOwnPropertyDescriptor(vCardPrototype,key)); }); setAllPropertiesEnumerable(lib.element.Button.prototype); - setAllPropertiesEnumerable(lib.element.Event.prototype); + setAllPropertiesEnumerable(lib.element.GameEvent.prototype); setAllPropertiesEnumerable(lib.element.Dialog.prototype); setAllPropertiesEnumerable(lib.element.Control.prototype); setAllPropertiesEnumerable(lib.element.Client.prototype); diff --git a/layout/default/layout.css b/layout/default/layout.css index e9139f1b5..d0ddebad6 100644 --- a/layout/default/layout.css +++ b/layout/default/layout.css @@ -1178,8 +1178,9 @@ body>.background.upper { z-index: -4 } body>.background.land { + background-position: center; + background-size: cover; transition: all 2s; - background-size:cover; } .popup:not(.guanxing) { @@ -3500,9 +3501,13 @@ div:not(.handcards)>.card>.info>span, animation: config 0.5s; -webkit-animation: config 0.5s; } -.flash { - animation: flash 1s; - -webkit-animation: flash 1s; +.flash, +.flash-animation-iteration-count-infinite { + animation-name: flash; + animation-duration: 1s; +} +.flash-animation-iteration-count-infinite { + animation-iteration-count: infinite; } .flip { animation: flip 1s; @@ -3884,6 +3889,10 @@ div:hover>.intro { .player .identity[data-color="zhu"], .player .identity[data-color="truezhu"], .player .identity[data-color="enemy"], +div[data-nature='zhu'], +span[data-nature='zhu'], +div[data-nature='enemy'], +span[data-nature='enemy'], div[data-nature='fire'], span[data-nature='fire'] { text-shadow: black 0 0 1px,rgba(232, 53, 53,1) 0 0 2px,rgba(232, 53, 53,1) 0 0 5px,rgba(232, 53, 53,1) 0 0 10px, @@ -3936,6 +3945,8 @@ span[data-nature='firemx'] { .player .identity[data-color="qun"], .player .identity[data-color="neutral"], .player .identity[data-color="friend2"], +div[data-nature='zhong'], +span[data-nature='zhong'], div[data-nature='metal'], span[data-nature='metal'] { text-shadow: black 0 0 1px,rgba(255, 203, 0,1) 0 0 2px,rgba(255, 203, 0,1) 0 0 5px,rgba(255, 203, 0,1) 0 0 10px, @@ -4006,6 +4017,8 @@ span[data-nature='qunmm'] { .player .identity[data-color="rYe"], .player .identity[data-color="bYe"], .player .identity[data-color="jin"], +div[data-nature='nei'], +span[data-nature='nei'], div[data-nature='thunder'], span[data-nature='thunder'] { text-shadow: rgba(100, 74, 139,1) 0 0 2px,rgba(100, 74, 139,1) 0 0 5px,rgba(100, 74, 139,1) 0 0 10px, @@ -4041,6 +4054,8 @@ span[data-nature='kamimm'] { .player .identity[data-color="fan"], .player .identity[data-color="wu"], +div[data-nature='fan'], +span[data-nature='fan'], div[data-nature='wood'], span[data-nature='wood'] { text-shadow: rgba(57, 123, 4,1) 0 0 2px,rgba(57, 123, 4,1) 0 0 5px,rgba(57, 123, 4,1) 0 0 10px, @@ -4065,6 +4080,8 @@ span[data-nature='woodmm'] { .player .identity[data-color="falsezhu"], .player .identity[data-color="friend"], .water, +div[data-nature='friend'], +span[data-nature='friend'], div[data-nature='water'], span[data-nature='water'] { text-shadow: rgba(78, 117, 140,1) 0 0 2px,rgba(78, 117, 140,1) 0 0 5px,rgba(78, 117, 140,1) 0 0 10px, diff --git a/mode/doudizhu.js b/mode/doudizhu.js index 625669180..7aa489cf8 100644 --- a/mode/doudizhu.js +++ b/mode/doudizhu.js @@ -685,8 +685,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ var next=game.createEvent('chooseCharacter'); next.showConfig=true; next.addPlayer=function(player){ - var list=lib.config.mode_config.identity.identity[game.players.length-3].slice(0); - var list2=lib.config.mode_config.identity.identity[game.players.length-2].slice(0); + var list=get.identityList(game.players.length-1); + var list2=get.identityList(game.players.length); for(var i=0;igame.addGlobalSkill(globalSkill)); game.players.forEach(current=>{ current.storage.zhibi=[]; current.storage.zhibi_for=[]; current.markSkill('stratagem_fury'); }); - + setTimeout(function(){ ui.arena.classList.remove('choose-character'); },500); @@ -2085,10 +2082,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } "step 4" if(event.stratagemMode){ - var list=['stratagem_fury','stratagem_fury_insight','stratagem_expose','stratagem_shan_ai','stratagem_card_effect']; - for(var i=0;igame.addGlobalSkill(globalSkill)); game.players.forEach(i=>{ i.storage.zhibi=[]; i.storage.zhibi_for=[]; @@ -2531,14 +2525,14 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ },500); }); }, - neiDoCamouflage:function(){ - var next=game.createEvent('neiDoCamouflage'); + stratagemCamouflage:function(){ + var next=game.createEvent('stratagemCamouflage'); next.players=game.players.slice(); if(_status.connectMode){ - next.setContent('neiDoCamouflageOL'); + next.setContent('stratagemCamouflageOL'); } else{ - next.setContent('neiDoCamouflage'); + next.setContent('stratagemCamouflage'); } }, }, @@ -2593,11 +2587,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ sheshen:'舍身', sheshen_info:'锁定技,主公处于濒死状态即将死亡时,令主公+1体力上限,回复体力至X点(X为你的体力值数),获得你的所有牌,然后你死亡。', yexinbilu:'野心毕露', - stratagem_fury:'怒气', - stratagem_fury_insight:'洞察', - stratagem_fury_cost1:'1🔥', - stratagem_fury_cost2:'2🔥', - stratagem_fury_cost3:'3🔥', + stratagem_insight:'洞察' }, element:{ player:{ @@ -2608,17 +2598,6 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ next.setContent('stratagemInsight'); return next; }, - changeFury:function(num){ - var player=this; - if(!player.storage.stratagem_fury) player.storage.stratagem_fury=0; - var tmp=player.storage.stratagem_fury; - player.storage.stratagem_fury+=num; - player.storage.stratagem_fury=Math.max(Math.min(player.storage.stratagem_fury,_status.stratagemFuryMax),0); - var del=player.storage.stratagem_fury-tmp; - if(del===0) return; - game.log(player,del>=0?'获得了':'失去了',get.cnNumber(Math.abs(del))+'点怒气'); - player.markSkill('stratagem_fury'); - }, addExpose:function(num){ if(!game.zhu||!game.zhu.isZhu||!game.zhu.identityShown) return; if(typeof this.ai.shown=='number'&&!this.identityShown&&this.ai.shown<1){ @@ -2964,180 +2943,187 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } }, content:{ - stratagemInsight:function(event,map){ + stratagemInsight:event=>{ 'step 0' - // var player=map.player,target=map.target; - if(!player.storage.stratagem_fury){event.finish();return;} - // yield player.changeFury(-1); - player.changeFury(-1); + game.log(player,'洞察了',target,'与其的阵营关系'); 'step 1' - if(!player.storage.zhibi) player.storage.zhibi=[]; - if(!player.storage.zhibi.contains(target)) player.storage.zhibi.push(target); - var res=get.insightResult(player,target); - event.insightResult=res; - + var storage=player.storage; + if(!storage.zhibi) storage.zhibi=[]; + var zhibi=storage.zhibi; + if(!zhibi.includes(target)) zhibi.push(target); + var insightResult=event.insightResult=get.insightResult(player,target); event.videoId=lib.status.videoId++; - var send=(target,res,id)=>{ - var str=get.translation(target)+'是'+get.translation(res+'2')+'
    '; - var dialog=ui.create.dialog(str,'forcebutton'); - ui.create.spinningIdentityCard(res,dialog); + var send=(clientTarget,clientInsightResult,id)=>{ + var classList=clientTarget.classList,nonStratagemInsightFlashing=classList.contains('flash-animation-iteration-count-infinite'); + if(nonStratagemInsightFlashing) clientTarget.nonStratagemInsightFlashing=true; + else classList.add('flash-animation-iteration-count-infinite'); + var identity=get.translation(`${clientInsightResult}2`); + clientTarget.prompt(identity,clientInsightResult); + var dialog=ui.create.dialog(`${get.translation(clientTarget)}是${identity}
    `,'forcebutton'); + ui.create.spinningIdentityCard(clientInsightResult,dialog); var control=ui.create.control('ok',()=>{ dialog.close(); control.close(); _status.imchoosing=false; - _status.event._result={bool:true}; + _status.event._result={ + bool:true + }; game.resume(); }); dialog.videoId=id; game.pause(); game.countChoose(); }; - var hint=(player,target,id)=>{ - if(player==game.me) return; - var str=get.translation(player)+'正在洞察'+get.translation(target)+'的阵营...
    '; - ui.create.dialog(str).videoId=id; - }; - - game.broadcastAll(hint,player,target,event.videoId); - if(event.isMine()){ - send(target,res,event.videoId); - } + game.broadcastAll((clientPlayer,clientTarget,id)=>{ + if(clientPlayer!=game.me) ui.create.dialog(`${get.translation(clientPlayer)}正在洞察${get.translation(clientTarget)}的阵营...
    `).videoId=id; + },player,target,event.videoId); + if(event.isMine()) send(target,insightResult,event.videoId); else if(event.isOnline()){ - event.player.send(send,target,res,event.videoId); - event.player.wait(); + player.send(send,target,insightResult,event.videoId); + player.wait(); game.pause(); } - // yield next; 'step 2' game.broadcastAll('closeDialog',event.videoId); - if(!_status.connectMode&&get.config('auto_mark_identity')&&!target.node.identity.firstChild.innerHTML.length){ - game.broadcastAll(function(player,target,event){ - if(player.isUnderControl(true)) target.setIdentity(event.insightResult); - },player,target,event); - } - }, - neiDoCamouflage:function(){ - 'step 0' - var list=[]; - for(var i=0;i{ + if(clientPlayer.isUnderControl(true)) clientTarget.setIdentity(insightResult); + },player,target,event.insightResult); + var afterInsight=clientTarget=>{ + clientTarget.unprompt(); + if(clientTarget.nonStratagemInsightFlashing){ + delete clientTarget.nonStratagemInsightFlashing; + return; } - } - var target=list.randomGet(); - event.target=target; - target.ai.stratagemCamouflage=true; - var neis=game.filterPlayer(i=>i.identity=='nei'); - if(event.players.includes(game.me)&&game.me.identity=='nei'){ - var str=get.translation(target)+'是反贼
    '; + var classList=clientTarget.classList; + if(classList.contains('flash-animation-iteration-count-infinite')) classList.remove('flash-animation-iteration-count-infinite'); + }; + if(event.isMine()) afterInsight(target); + else if(event.isOnline()) player.send(afterInsight,target); + }, + stratagemCamouflage:()=>{ + 'step 0' + var camouflaged=event.targets=game.players.filter(current=>current.identity=='fan'&&!current.ai.stratagemCamouflage).randomGets(Math.max(Math.round(get.population()/6),1)); + camouflaged.forEach(current=>current.ai.stratagemCamouflage=true); + var me=game.me; + if(event.players.includes(me)&&me.identity=='nei'){ event.videoId=lib.status.videoId++; - var dialog=ui.create.dialog(str,'forcebutton'); + var rebel=get.translation('fan2'),dialog=ui.create.dialog(`${get.translation(camouflaged)}是${rebel}
    `,'forcebutton'); ui.create.spinningIdentityCard('fan',dialog); dialog.videoId=event.videoId; - game.me.chooseControl('ok').set('dialog',dialog); - } - for(var current of neis){ - if(!current.storage.zhibi) current.storage.zhibi=[]; - if(!current.storage.zhibi.includes(target)) current.storage.zhibi.push(target); + camouflaged.forEach(victim=>{ + var classList=victim.classList,nonCamouflageFlashing=classList.contains('flash-animation-iteration-count-infinite'); + if(nonCamouflageFlashing) victim.nonCamouflageFlashing=true; + else classList.add('flash-animation-iteration-count-infinite'); + victim.prompt(rebel,'fan'); + }); + me.chooseControl('ok').set('dialog',dialog); } + game.filterPlayer(current=>{ + if(current.identity!='nei') return; + var storage=current.storage; + if(!storage.zhibi) storage.zhibi=[]; + storage.zhibi.addArray(camouflaged); + }); 'step 1' - if(game.me.identity=='nei'&&get.config('nei_auto_mark_camouflage')){ - event.target.setIdentity(); - } + targets.forEach(current=>{ + if(game.me.identity=='nei'&&get.config('nei_auto_mark_camouflage')) current.setIdentity(); + current.unprompt(); + if(current.nonCamouflageFlashing){ + delete current.nonCamouflageFlashing; + return; + } + var classList=current.classList; + if(classList.contains('flash-animation-iteration-count-infinite')) classList.remove('flash-animation-iteration-count-infinite'); + }); }, - neiDoCamouflageOL:function(){ + stratagemCamouflageOL:()=>{ 'step 0' - var send=function(target,id){ - if(game.me.identity=='nei'){ - if(!game.me.storage.zhibi) game.me.storage.zhibi=[]; - if(!game.me.storage.zhibi.contains(target)) game.me.storage.zhibi.push(target); - var str=get.translation(target)+'是反贼
    '; - var dialog=ui.create.dialog(str,'forcebutton'); + var send=(clientCamouflaged,id,online)=>{ + var me=game.me; + if(me.identity=='nei'){ + var storage=me.storage; + if(!storage.zhibi) storage.zhibi=[]; + storage.zhibi.addArray(clientCamouflaged); + var rebel=get.translation('fan2'),dialog=ui.create.dialog(`${get.translation(clientCamouflaged)}是${rebel}
    `,'forcebutton'); ui.create.spinningIdentityCard('fan',dialog); dialog.videoId=id; - game.me.chooseControl('ok').set('dialog',dialog); + clientCamouflaged.forEach(victim=>{ + var classList=victim.classList,nonCamouflageFlashing=classList.contains('flash-animation-iteration-count-infinite'); + if(nonCamouflageFlashing) victim.nonCamouflageFlashing=true; + else classList.add('flash-animation-iteration-count-infinite'); + victim.prompt(rebel,'fan'); + }); + me.chooseControl('ok').set('dialog',dialog); } - else{ - var dialog=ui.create.dialog('请等待内奸身份确认...'); - dialog.videoId=id; - } - game.resume(); + else ui.create.dialog('请等待内奸身份确认...').videoId=id; + if(online) game.resume(); }; - var list=[]; - for(var i=0;icurrent.identity=='fan'&&!current.ai.stratagemCamouflage).randomGets(Math.max(Math.round(get.population()/6),1)); + camouflaged.forEach(current=>current.ai.stratagemCamouflage=true); event.videoId=lib.status.videoId++; - event.ai_targets=[]; var time=10000; if(lib.configOL&&lib.configOL.choose_timeout) time=parseInt(lib.configOL.choose_timeout)*1000; - for(var i=0;i{ + current.showTimer(time); + if(current.isOnline()){ + current.send(send,camouflaged,event.videoId,true); + current.wait(); + if(current.identity=='nei') event.withOL=true; + return; } - else if(event.players[i]==game.me){ - event.withme=true; - if(game.me.identity=='nei'){ - var str=get.translation(target)+'是反贼
    '; - var dialog=ui.create.dialog(str,'forcebutton'); - ui.create.spinningIdentityCard('fan',dialog); - dialog.videoId=event.videoId; - game.me.chooseControl('ok').set('dialog',dialog); - game.me.wait(); - } - else{ - var dialog=ui.create.dialog('请等待内奸身份确认...'); - dialog.videoId=event.videoId; - event._result={bool:true}; - } + var me=game.me; + if(current==me){ + event.withMe=true; + send(camouflaged,event.videoId); + if(me.identity=='nei') me.wait(); + else event._result={ + bool:true + }; + return; } - else{ - if(event.players[i].identity=='nei'){ - event.ai_targets.push(event.players[i]); - } - } - } - if(event.ai_targets.length){ - event.ai_targets.randomSort(); - setTimeout(function(){ - event.interval=setInterval(function(){ - event.ai_targets.shift(); - if(!event.ai_targets.length){ - clearInterval(event.interval); - if(event.withai) game.resume(); - } - },Math.ceil(100+500*Math.random())); - },Math.ceil(2500+1000*Math.random())) - } + if(current.identity=='nei') aiTargets.push(current); + }); + if(!aiTargets.length) return; + aiTargets.randomSort(); + new Promise(resolve=>setTimeout(resolve,Math.ceil(5000+5000*Math.random()))).then(()=>{ + var interval=setInterval(()=>{ + aiTargets.shift(); + if(aiTargets.length) return; + clearInterval(interval); + if(event.withAI) game.resume(); + },Math.ceil(500+500*Math.random())) + }); 'step 1' - if(event.withme){ - game.me.unwait(result); - } + if(event.withMe) game.me.unwait(result); 'step 2' - if(event.withol&&!event.resultOL){ - game.pause(); - } + if(event.withOL&&!event.resultOL) game.pause(); 'step 3' - if(event.ai_targets.length>0){ - event.withai=true; - game.pause(); - } + if(!event.aiTargets.length) return; + event.withAI=true; + game.pause(); 'step 4' game.broadcastAll('closeDialog',event.videoId); - for(var i=0;icurrent.hideTimer()); + var afterCamouflage=clientCamouflaged=>clientCamouflaged.forEach(victim=>{ + victim.unprompt(); + if(victim.nonCamouflageFlashing){ + delete victim.nonCamouflageFlashing; + return; + } + var classList=victim.classList; + if(classList.contains('flash-animation-iteration-count-infinite')) classList.remove('flash-animation-iteration-count-infinite'); + }); + event.players.forEach(current=>{ + if(current.isOnline()){ + current.send(afterCamouflage,targets); + return; + } + var me=game.me; + if(current==me&&me.identity=='nei') afterCamouflage(targets); + }); + } + } }, get:{ rawAttitude:function(from,to){ @@ -3194,7 +3180,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } if(to.identity=='fan'&&from.identity=='nei'&&zhibi.contains(game.zhu)&&game.players.filter(i=>i!=from&&!zhibi.contains(i)).map(i=>i.identity).reduce((p,c)=>(!p.contains(c)?(p.push(c)&&p):p),[]).length==1) return real; for(var fan of game.dead){ - if(fan.identity!='fan'||!fan.storage.stratagem_show_fan) continue; + if(fan.identity!='fan'||!fan.storage.stratagem_revitalization) continue; for(var current of fan.storage.zhibi_for){ if(to==current){ return real; @@ -3705,86 +3691,51 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(from.ai.stratagemCamouflage||to.ai.stratagemCamouflage) return enemy; if(from.identity==to.identity||from.identity=='zhu'&&to.identity=='zhong'||from.identity=='zhong'&&to.identity=='zhu') return friend; return enemy; - }, - /** - * @param {number} numberOfPlayers - * @returns {string[]} - */ - identityList:numberOfPlayers=>{ - const modeConfig=lib.config.mode_config; - if(modeConfig){ - const identityConfig=modeConfig.identity; - if(identityConfig){ - const identityLists=identityConfig.identity; - if(identityLists){ - const identityList=identityLists[numberOfPlayers-2]; - if(Array.isArray(identityList)) return identityList.slice(); - } - } - } - const numberOfPlayersExceptLord=numberOfPlayers-1,numberOfLoyalists=Math.round(numberOfPlayersExceptLord*3/9),numberOfSpys=Math.round(numberOfPlayersExceptLord*2/9); - return ['zhu'].concat(Array.from({ - length:numberOfLoyalists - },()=>'zhong'),Array.from({ - length:numberOfSpys - },()=>'nei'),Array.from({ - length:numberOfPlayersExceptLord-numberOfLoyalists-numberOfSpys - },()=>'fan')); } }, skill:{ - stratagem_fury:{ - mark:true, - marktext:'🔥', + stratagem_gain:{ silent:true, charlotte:true, ruleSkill:true, trigger:{ - player:['phaseBegin','damageEnd'], + player:['phaseBegin','damageEnd'] }, - content:function(){ - player.changeFury(trigger.name=='damage'?trigger.num:1); - }, - intro:{ - name:'怒气', - content:function(storage,player){ - return '当前怒气值:'+(storage||0)+'/'+_status.stratagemFuryMax; - }, - }, - subSkill:{ - insight:{ - trigger:{ - source:'damageSource', - global:'loseHpEnd', - }, - filter:function(event,player){ - if(event.player.identityShown) return false; - var source=event.source; - if(event.name=='loseHp'){ - if(event.getParent()._trigger) source=event.getParent()._trigger.source; - } - return player==source&&player.storage.stratagem_fury>0&&event.player&&event.player.isIn()&&event.player!=player; - }, - logTarget:'player', - prompt2:function(event,player){ - return '消耗1点怒气,洞察'+get.translation(event.player)+'的身份'; - }, - check:function(event,player){ - if(player.storage.zhibi&&player.storage.zhibi.contains(event.player)||player.storage.zhibi_for&&player.storage.zhibi_for.contains(event.player)) return false; - if(get.population('zhong')==0&&player.identity=='fan') return false; - return Math.abs(get.attitude(player,event.player))<=1; - }, - content:function(){ - game.log(player,'洞察了',trigger.player,'与其的阵营关系'); - player.insightInto(trigger.player); - }, - ai:{ - order:15, - } - }, + content:()=>{ + player.changeFury(trigger.name=='damage'?trigger.num:1,true); } }, - stratagem_show_zhu:{ + stratagem_insight:{ + trigger:{ + source:'damageSource', + global:'loseHpEnd', + }, + filter:function(event,player){ + if(event.player.identityShown) return false; + var source=event.source; + if(event.name=='loseHp'){ + if(event.getParent()._trigger) source=event.getParent()._trigger.source; + } + return player==source&&player.storage.stratagem_fury>0&&event.player&&event.player.isIn()&&event.player!=player; + }, + logTarget:'player', + prompt2:function(event,player){ + return '消耗1点怒气,洞察'+get.translation(event.player)+'的身份'; + }, + check:function(event,player){ + if(player.storage.zhibi&&player.storage.zhibi.contains(event.player)||player.storage.zhibi_for&&player.storage.zhibi_for.contains(event.player)) return false; + if(get.population('zhong')==0&&player.identity=='fan') return false; + return Math.abs(get.attitude(player,event.player))<=1; + }, + content:function(){ + player.changeFury(-1,true); + player.insightInto(trigger.player); + }, + ai:{ + order:15, + } + }, + stratagem_monarchy:{ trigger:{ player:['dying','phaseBefore'], global:'dieAfter', @@ -3798,7 +3749,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ charlotte:true, ruleSkill:true, filter:function(event,player){ - if(player.storage.stratagem_show_zhu) return false; + if(player.storage.stratagem_monarchy) return false; if(player.identity=='zhu'){ if(event.player==player){ if(event.name=='dying') return true; @@ -3812,7 +3763,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ 'step 0' if(trigger.name=='dying') game.delayx(); 'step 1' - player.storage.stratagem_show_zhu=true; + player.storage.stratagem_monarchy=true; game.zhu=game.zhu||player; game.broadcastAll(function(player){ game.zhu=player; @@ -3847,7 +3798,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } }, - stratagem_show_fan:{ + stratagem_revitalization:{ trigger:{ player:'dying', }, @@ -3857,13 +3808,13 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ charlotte:true, ruleSkill:true, filter:function(event,player){ - return player.ai.stratagemCamouflage&&event.player==player&&!game.dead.length&&player.storage.stratagem_fury>=2&&!player.storage.stratagem_show_fan; + return player.ai.stratagemCamouflage&&event.player==player&&game.dead.length=2&&!player.storage.stratagem_revitalization; }, content:function(){ 'step 0' game.delayx(); 'step 1' - player.storage.stratagem_show_fan=true; + player.storage.stratagem_revitalization=true; game.broadcastAll(function(player){ player.identityShown=true; player.ai.shown=1; @@ -3875,7 +3826,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ game.delay(2); player.playerfocus(800); 'step 2' - player.changeFury(-player.storage.stratagem_fury); + player.changeFury(-player.storage.stratagem_fury,true); player.discard(player.getCards('hej')); player.link(false); player.turnOver(false); @@ -3891,76 +3842,12 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ filter:function(event,player){ if(event.targets[0]==player) return false; return event.targets.length==1&&event.targets[0]&&((player.storage.zhibi.contains(event.targets[0])||event.targets[0].identityShown) || - game.players.slice().concat(game.dead).filter(current=>(current.storage.stratagem_show_fan||current.storage.stratagem_show_zhu)&¤t.identityShown&¤t.storage.zhibi_for.contains(event.targets[0])).length); + game.players.slice().concat(game.dead).filter(current=>(current.storage.stratagem_revitalization||current.storage.stratagem_monarchy)&¤t.identityShown&¤t.storage.zhibi_for.contains(event.targets[0])).length); }, content:function(){ if(!trigger.targets[0].storage.zhibi_for) trigger.targets[0].storage.zhibi_for=[]; if(!trigger.targets[0].storage.zhibi_for.contains(player)) trigger.targets[0].storage.zhibi_for.push(player); } - - }, - stratagem_shan_ai:{ - trigger:{ - player:'chooseToUseBegin', - }, - filter:function(event,player){ - if(event.getParent().name!='sha') return false; - return event.getParent().target==player; - }, - forced:true, - silent:true, - forced:true, - charlotte:true, - content:function(){ - var evt=trigger.getParent(); - trigger.set('prompt','请使用一张闪响应杀'); - trigger.set('filterCard',function(card,player){ - if(get.name(card)!='shan') return false; - return lib.filter.cardEnabled(card,player,'forceEnable'); - }); - var req=evt.shanRequired; - if(req>1){ - trigger.set('prompt2','(共需使用'+req+'张普通闪,或'+Math.ceil(req/2)+'张强化闪)'); - } - else if(evt.card.nature=='stab'){ - trigger.set('prompt2','(在此之后仍需弃置一张手牌)'); - } - trigger.set('ai1',function(card){ - var target=_status.event.player; - var evt=_status.event.getParent(2); - var bool=true; - if(_status.event.getParent().shanRequired>1&&!get.is.object(card)&&(target.countCards('h','shan')<_status.event.getParent().shanRequired&&!(target.storage.stratagem_fury>=1&&target.countCards('h','shan')==1&&_status.event.getParent().shanRequired<=2))){ - bool=false; - } - else if(target.hasSkillTag('useShan')){ - bool=true; - } - else if(get.damageEffect(target,evt.player,target,evt.card.nature)>=0) bool=false; - if(bool){ - return get.order(card); - } - return 0; - }).set('shanRequired',evt.shanRequired); - }, - }, - stratagem_card_effect:{ - trigger:{ - player:['useCard1'], - }, - forced:true, - silent:true, - forced:true, - charlotte:true, - filter:function(event,player,name){ - return event.card&&event.card.storage&&event.card.storage.stratagemBuffed&&event.cards.length; - }, - content:function(){ - game.broadcastAll(function(cards){ - for(var i of cards){ - i.clone.classList.add('stratagem-fury-glow'); - } - },trigger.cards); - } }, yexinbilu:{ enable:'phaseUse', From f976299a0ebadfeb68385cb43ce4a067a3c77540 Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Mon, 23 Oct 2023 20:13:00 -0700 Subject: [PATCH 5/6] Optimize code and fix more bugs. --- game/game.js | 125 +++++++++++++++++++--------------- mode/identity.js | 170 +++++++++++++++++++++++------------------------ 2 files changed, 157 insertions(+), 138 deletions(-) diff --git a/game/game.js b/game/game.js index 93122aa72..d988de5cb 100644 --- a/game/game.js +++ b/game/game.js @@ -625,7 +625,9 @@ ['sha',event=>{ if(event.step!=1) return; game.log(event.player,'触发了强化效果'); - game.log(event.card,'抵消所需要的',`#y【${get.translation('shan')}】`,'数+1'); + 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; @@ -637,8 +639,12 @@ ['shan',event=>{ if(event.step!=1) return; game.log(event.player,'触发了强化效果'); - game.log(event.card,'视为两张',`#y【${get.translation('shan')}】`,'的效果'); - event.getParent(2).decrease('shanRequired',1); + 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=>{ if(event.step!=1) return; @@ -25344,55 +25350,37 @@ return next; } damage(){ - var next=game.createEvent('damage'); + const next=game.createEvent('damage'); //next.forceDie=true; next.player=this; - var nocard,nosource; - var event=_status.event; - for(var i=0;i | Function | keyof typeof lib.element.content} item + */ setContent(item){ switch(typeof item){ case "object": @@ -31500,6 +31491,7 @@ } /** * @throws {'Do not call this method'} + * @returns {never} */ typeAnnotation(){ /** @@ -31546,6 +31538,34 @@ * @type {Record} */ this._result; + /** + * @type {number} + */ + this.baseDamage; + /** + * @type {Player} + */ + this.customSource; + /** + * @type {number} + */ + this.extraDamage; + /** + * @type {string} + */ + this.nature; + /** + * @type {boolean} + */ + this.notrigger; + /** + * @type {number} + */ + this.original_num; + /** + * @type {boolean} + */ + this.unreal; throw 'Do not call this method'; } }, @@ -53988,9 +54008,8 @@ list2.push(list2[0]); for(var i=0;igame.addGlobalSkill(globalSkill)); game.players.forEach(current=>{ current.storage.zhibi=[]; - current.storage.zhibi_for=[]; + current.storage.stratagem_expose=[]; current.markSkill('stratagem_fury'); }); @@ -2085,7 +2085,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ ['stratagem_gain','stratagem_insight','stratagem_expose'].forEach(globalSkill=>game.addGlobalSkill(globalSkill)); game.players.forEach(i=>{ i.storage.zhibi=[]; - i.storage.zhibi_for=[]; + i.storage.stratagem_expose=[]; i.markSkill('stratagem_fury'); }); } @@ -3159,9 +3159,9 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(num){ return x/num; } - var real=get.realAttitude(from,to),zhibi=from.storage.zhibi,zhibi_for=from.storage.zhibi_for,followCamouflage=true; + var real=get.realAttitude(from,to),zhibi=from.storage.zhibi,stratagem_expose=from.storage.stratagem_expose,followCamouflage=true; if(to.ai.shown) return to.ai.shown*(real+(from.identity==to.identity||from.identity=='zhu'&&to.identity=='zhong'||from.identity=='zhong'&&to.identity=='zhu'||(to.identity=='nei'&&get.situation()<=0&&['zhu','zhong'].contains(from.identity)||get.situation()>=3&&from.identity=='fan')?3:-3)) - if(from==to||to.identityShown||((zhibi_for&&zhibi_for.contains(to))||(zhibi&&zhibi.contains(to)))&&!to.ai.stratagemCamouflage) return real*1.1; + if(from==to||to.identityShown||((stratagem_expose&&stratagem_expose.contains(to))||(zhibi&&zhibi.contains(to)))&&!to.ai.stratagemCamouflage) return real*1.1; if(from.identity=='nei'&&to.ai.stratagemCamouflage) return real*1.1; if(to.identity=='nei'){ if(from.identity=='fan'){ @@ -3170,7 +3170,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ var dead=game.dead.slice(); for(var current of dead){ if(from.storage.zhibi.contains(current)&¤t.ai.stratagemCamouflage){ - if(from.storage.zhibi_for&&from.storage.zhibi_for.contains(to)) return -7; + if(from.storage.stratagem_expose&&from.storage.stratagem_expose.contains(to)) return -7; } } if(zhibi.contains(to)) return 3; @@ -3181,7 +3181,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(to.identity=='fan'&&from.identity=='nei'&&zhibi.contains(game.zhu)&&game.players.filter(i=>i!=from&&!zhibi.contains(i)).map(i=>i.identity).reduce((p,c)=>(!p.contains(c)?(p.push(c)&&p):p),[]).length==1) return real; for(var fan of game.dead){ if(fan.identity!='fan'||!fan.storage.stratagem_revitalization) continue; - for(var current of fan.storage.zhibi_for){ + for(var current of fan.storage.stratagem_expose){ if(to==current){ return real; } @@ -3191,26 +3191,26 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ if(from.ai.stratagemCamouflage){ var zhu=game.zhu&&game.zhu.isZhu&&game.zhu.identityShown?game.zhu:undefined; if(zhu){ - if(zhu.storage.zhibi_for&&zhu.storage.zhibi_for.contains(to)) return 0; + if(zhu.storage.stratagem_expose&&zhu.storage.stratagem_expose.contains(to)) return 0; } if(zhibi&&zhibi.contains(to)) return -7; } if(to.ai.stratagemCamouflage){ var zhu=game.zhu&&game.zhu.isZhu&&game.zhu.identityShown?game.zhu:undefined; if(zhu){ - if(zhu.storage.zhibi_for&&zhu.storage.zhibi_for.contains(to)) return 0; + if(zhu.storage.stratagem_expose&&zhu.storage.stratagem_expose.contains(to)) return 0; } if(zhibi&&zhibi.contains(to)) return -7; } } if(from.identity!='nei'&&zhibi&&zhibi.contains(to)&&!to.identityShown&&(followCamouflage&&to.ai.stratagemCamouflage)) return -5; - if(from.identity!='nei'&&zhibi_for&&zhibi_for.contains(to)&&!to.identityShown) return -5; + if(from.identity!='nei'&&stratagem_expose&&stratagem_expose.contains(to)&&!to.identityShown) return -5; if(zhibi){ for(var to2 of zhibi){ - if(to2.storage.zhibi_for){ + if(to2.storage.stratagem_expose){ if(to2.ai.stratagemCamouflage){ - for(var to3 of to2.storage.zhibi_for){ - if(zhibi.slice().addArray(zhibi_for).contains(to3)){ + for(var to3 of to2.storage.stratagem_expose){ + if(zhibi.slice().addArray(stratagem_expose).contains(to3)){ if(to==to2){ return real; } @@ -3219,8 +3219,8 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ } } }else{ - for(var to3 of to2.storage.zhibi_for){ - if(!zhibi.slice().addArray(zhibi_for).contains(to3)&&to==to3){ + for(var to3 of to2.storage.stratagem_expose){ + if(!zhibi.slice().addArray(stratagem_expose).contains(to3)&&to==to3){ return get.rawAttitude(to3,to)*Math.sign(real); } } @@ -3708,36 +3708,37 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ stratagem_insight:{ trigger:{ source:'damageSource', - global:'loseHpEnd', + global:'loseHpEnd' }, - filter:function(event,player){ - if(event.player.identityShown) return false; - var source=event.source; + filter:(event,player)=>{ + if(!player.storage.stratagem_fury) return false; + const target=event.player; + if(target==player||!target.isIn()||target.identityShown) return false; + let source=event.source; if(event.name=='loseHp'){ - if(event.getParent()._trigger) source=event.getParent()._trigger.source; + const trigger=event.getParent()._trigger; + if(trigger) source=trigger.source; } - return player==source&&player.storage.stratagem_fury>0&&event.player&&event.player.isIn()&&event.player!=player; + return player==source; }, logTarget:'player', - prompt2:function(event,player){ - return '消耗1点怒气,洞察'+get.translation(event.player)+'的身份'; - }, - check:function(event,player){ - if(player.storage.zhibi&&player.storage.zhibi.contains(event.player)||player.storage.zhibi_for&&player.storage.zhibi_for.contains(event.player)) return false; + prompt2:event=>`消耗1点怒气,洞察${get.translation(event.player)}的身份`, + check:(event,player)=>{ + const storage=player.storage,zhibi=storage.zhibi; + if(zhibi&&zhibi.includes(event.player)) return false; + const stratagemExpose=storage.stratagem_expose; + if(stratagemExpose&&stratagemExpose.includes(event.player)) return false; if(get.population('zhong')==0&&player.identity=='fan') return false; return Math.abs(get.attitude(player,event.player))<=1; }, - content:function(){ + content:()=>{ player.changeFury(-1,true); player.insightInto(trigger.player); - }, - ai:{ - order:15, } }, stratagem_monarchy:{ trigger:{ - player:['dying','phaseBefore'], + player:['dying','phaseZhunbeiBegin'], global:'dieAfter', }, forced:true, @@ -3748,54 +3749,46 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ silent:true, charlotte:true, ruleSkill:true, - filter:function(event,player){ - if(player.storage.stratagem_monarchy) return false; - if(player.identity=='zhu'){ - if(event.player==player){ - if(event.name=='dying') return true; - return game.roundNumber>=Math.max(Math.round(get.population()/2),3); - } - if(event.name=='die') return game.dead.length>=Math.max(Math.round(get.population()/3),2); - } - return false; + filter:(event,player,name)=>{ + if(player.storage.stratagem_monarchy||player.identity!='zhu') return false; + if(name=='dieAfter') return game.dead.length>=Math.max(Math.round(get.population()/3),2); + return name=='dying'||game.roundNumber>=Math.max(Math.round(get.population()/2),3); }, - content:function(){ + content:()=>{ 'step 0' - if(trigger.name=='dying') game.delayx(); + if(event.triggername=='dying') game.delayx(); 'step 1' player.storage.stratagem_monarchy=true; - game.zhu=game.zhu||player; - game.broadcastAll(function(player){ - game.zhu=player; - game.zhu.identityShown=true; - game.zhu.ai.shown=1; - game.zhu.setIdentity(); - game.zhu.isZhu=true; - game.zhu.node.identity.classList.remove('guessing'); - if(lib.config.animation&&!lib.config.low_performance) game.zhu.$legend(); - if(_status.clickingidentity&&_status.clickingidentity[0]==game.zhu){ - for(var i=0;i<_status.clickingidentity[1].length;i++){ - _status.clickingidentity[1][i].delete(); - _status.clickingidentity[1][i].style.transform=''; - } - delete _status.clickingidentity; - } - },game.zhu); + game.broadcastAll(clientPlayer=>{ + if(!game.zhu) game.zhu=clientPlayer; + clientPlayer.identityShown=true; + clientPlayer.ai.shown=1; + clientPlayer.setIdentity(); + clientPlayer.isZhu=true; + clientPlayer.node.identity.classList.remove('guessing'); + var config=lib.config; + if(config.animation&&!config.low_performance) clientPlayer.$legend(); + var clickingIdentity=_status.clickingidentity; + if(!clickingIdentity||clickingIdentity[0]!=clientPlayer) return; + clickingIdentity[1].forEach(element=>{ + element.delete(); + element.style.transform=''; + }); + delete _status.clickingidentity; + },player); game.addVideo('showIdentity',player,'zhu'); game.delay(2); - game.zhu.playerfocus(1000); - _status.event.trigger('zhuUpdate'); + player.playerfocus(1000); + event.trigger('zhuUpdate'); 'step 2' player.recover(); player.draw(); - var skills=player.getStockSkills(true,true).filter(skill=>{ - if(player.hasSkill(skill)) return false; - var info=get.info(skill); - return info&&info.zhuSkill; + player.getStockSkills(true,true).forEach(stockSkill=>{ + if(player.hasSkill(stockSkill)) return; + var info=get.info(stockSkill); + if(!info||!info.zhuSkill) return; + player.addSkillLog(stockSkill); }); - if(skills.length){ - for(var i of skills) player.addSkillLog(i); - } } }, stratagem_revitalization:{ @@ -3807,20 +3800,21 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ silent:true, charlotte:true, ruleSkill:true, - filter:function(event,player){ - return player.ai.stratagemCamouflage&&event.player==player&&game.dead.length=2&&!player.storage.stratagem_revitalization; + filter:(event,player)=>{ + const storage=player.storage; + return !storage.stratagem_revitalization&&player.ai.stratagemCamouflage&&game.dead.length=2; }, - content:function(){ + content:()=>{ 'step 0' game.delayx(); 'step 1' player.storage.stratagem_revitalization=true; - game.broadcastAll(function(player){ - player.identityShown=true; - player.ai.shown=1; - player.setIdentity(); - player.node.identity.classList.remove('guessing'); - if(lib.config.animation&&!lib.config.low_performance) player.$thunder(); + game.broadcastAll(clientPlayer=>{ + clientPlayer.identityShown=true; + clientPlayer.ai.shown=1; + clientPlayer.setIdentity(); + clientPlayer.node.identity.classList.remove('guessing'); + if(lib.config.animation&&!lib.config.low_performance) clientPlayer.$thunder(); },player); game.addVideo('showIdentity',player,'fan'); game.delay(2); @@ -3839,14 +3833,20 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ forced:true, silent:true, popup:false, - filter:function(event,player){ - if(event.targets[0]==player) return false; - return event.targets.length==1&&event.targets[0]&&((player.storage.zhibi.contains(event.targets[0])||event.targets[0].identityShown) || - game.players.slice().concat(game.dead).filter(current=>(current.storage.stratagem_revitalization||current.storage.stratagem_monarchy)&¤t.identityShown&¤t.storage.zhibi_for.contains(event.targets[0])).length); + filter:(event,player)=>{ + const targets=event.targets; + if(targets.length!=1) return false; + const target=targets[0]; + return target==player&&(target.identityShown||player.storage.zhibi.includes(target)||game.hasPlayer2(current=>{ + if(!current.identityShown) return false; + const storage=current.storage; + return (storage.stratagem_revitalization||storage.stratagem_monarchy)&&storage.stratagem_expose.includes(target); + })); }, - content:function(){ - if(!trigger.targets[0].storage.zhibi_for) trigger.targets[0].storage.zhibi_for=[]; - if(!trigger.targets[0].storage.zhibi_for.contains(player)) trigger.targets[0].storage.zhibi_for.push(player); + content:()=>{ + var storage=trigger.targets[0].storage; + if(!storage.stratagem_expose) storage.stratagem_expose=[]; + storage.stratagem_expose.add(player); } }, yexinbilu:{ @@ -4095,7 +4095,7 @@ game.import('mode',function(lib,game,ui,get,ai,_status){ '谋攻模式':'
    模式命名由来
    • 《谋攻篇》一词出自《孙子兵法·谋攻篇》,是春秋时期兵法家孙武创作的一篇散文。《谋攻篇》故知胜有五:知可以战与不可以战者胜,识众寡之用者胜,上下同欲者胜,以虞待不虞者胜,将能而君不御者胜。
    '+ '
    游戏规则
    • 谋攻篇模式为六名玩家参与的全暗身份模式,引入新机制“怒气”,玩家可以消耗怒气探查其他角色的身份是敌人或者队友,或使用怒气强化手牌,以达到识别出队友并击杀敌人的目标。'+ '
    • 各身份玩家的胜利条件与身份局中对应身份的胜利条件一致,且该模式下没有奖惩。'+ - '
    • 当主公进入濒死、场上有两名角色阵亡、第三轮的主公回合开始时,主公将会翻开身份牌,回复1点体力并摸一张牌,并获得武将牌上的主公技。'+ + '
    • 当主公进入濒死、场上有两名角色阵亡、第三轮的主公准备阶段,主公将会翻开身份牌,回复1点体力并摸一张牌,并获得武将牌上的主公技。'+ '
    • 内奸在游戏开始时将会得知一名反贼的身份,并令该反贼被“伪装”。本局游戏内,被“伪装”的反贼在被任何人探查身份时,结果都提示为“敌人”。作为补偿,其第一次进入濒死时,若场上没有角色死亡且其怒气值不小于2,其弃置区域内所有牌,重置武将牌,将体力回复至2点并摸三张牌。'+ '
    • 特殊地,内奸在被所有角色探查时,都提示为“队友”;内奸在进行探查时,直接得知目标的身份。
    '+ '
    新机制“怒气”
    • 一名角色在回合开始时或受到1点伤害后,将获得1点怒气;怒气上限为3。
    • 一名角色令其他角色扣减体力后,该角色可以消耗1点怒气,查探扣减体力的角色是敌或友。
    '+ From 46dd32788732bcd41a3e8c3e85f568a6bb35c4b3 Mon Sep 17 00:00:00 2001 From: Tipx-L <138244655+Tipx-L@users.noreply.github.com> Date: Mon, 23 Oct 2023 21:02:37 -0700 Subject: [PATCH 6/6] Fix `updateTransform`. --- game/game.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/game/game.js b/game/game.js index d988de5cb..c4e80fc49 100644 --- a/game/game.js +++ b/game/game.js @@ -30621,6 +30621,9 @@ } _status.event.excludeButton.add(this); } + get updateTransform(){ + return lib.element.Card.prototype.updateTransform; + } }, GameEvent:class{ /** @@ -43250,21 +43253,17 @@ //创建身份牌实例 identityCard:function(identity,position,info,noclick){ const card=ui.create.card(position,info,noclick); - card._customintro=function(uiintro){ - uiintro.add(`${get.translation(identity+2)}的身份牌`); - } + card._customintro=uiintro=>uiintro.add(`${get.translation(`${identity}${2}`)}的身份牌`); const fileName=`image/card/identity_${identity}.jpg`; new Promise((resolve,reject)=>{ const image=new Image(); - image.onload=()=>resolve(); + image.onload=resolve; image.onerror=reject; image.src=`${lib.assetURL}${fileName}`; }).then(()=>{ card.classList.add('fullskin'); card.node.image.setBackgroundImage(fileName); - }).catch(()=>{ - card.node.background.innerHTML=get.translation(identity)[0]; - }); + },()=>card.node.background.innerHTML=get.translation(identity)[0]); return card; }, //让卡牌旋转