diff --git a/game/game.js b/game/game.js index 74dadb300..5f4bd5766 100644 --- a/game/game.js +++ b/game/game.js @@ -1,5 +1,12 @@ "use strict"; { + /** + * @typedef {InstanceType} Player + * @typedef {InstanceType} Card + * @typedef {InstanceType} VCard + * @typedef {InstanceType} GameEvent + * @typedef {InstanceType} NodeWS + */ const userAgent=navigator.userAgent.toLowerCase(); if(!localStorage.getItem('gplv3_noname_alerted')){ if(confirm('①无名杀是一款基于GPLv3协议的开源软件!\n你可以在遵守GPLv3协议的基础上任意使用,修改并转发《无名杀》,以及所有基于《无名杀》开发的拓展。\n点击“确定”即代表您认可并接受GPLv3协议↓️\nhttps://www.gnu.org/licenses/gpl-3.0.html\n②无名杀官方发布地址仅有GitHub仓库!\n其他所有的所谓“无名杀”社群(包括但不限于绝大多数“官方”QQ群、QQ频道等)均为玩家自发组织,与无名杀官方无关!')){ @@ -77,11 +84,10 @@ over:false, clicked:false, auto:false, - event:{ - finished:true, - next:[], - after:[] - }, + /** + * @type {GameEvent} + */ + event:null, ai:{}, lastdragchange:[], skillaudio:[], @@ -7485,6 +7491,9 @@ '
  • 激昂:一名角色发动“昂扬技”标签技能后,此技能失效,直至从此刻至满足此技能“激昂”条件后。'+ '' }, + /** + * @type {import('path')} + */ path:{}, getErrorTip:msg=>{ if(typeof msg!='string'){ @@ -7944,7 +7953,7 @@ setScroll:function(node){ node.ontouchstart=ui.click.touchStart; node.ontouchmove=ui.click.touchScroll; - node.style.WebkitOverflowScrolling='touch'; + node.style.webkitOverflowScrolling='touch'; return node; }, setMousewheel:function(node){ @@ -8234,9 +8243,7 @@ lib.ui=ui; lib.ai=ai; lib.game=game; - for(let i in lib.element.event){ - _status.event[i]=lib.element.event[i]; - } + _status.event=new lib.element.Event().finish(); HTMLDivElement.prototype.animate=function(name,time){ var that; @@ -8552,7 +8559,7 @@ } }); /** - *@legacy Use `Array.prototype.includes(searchElement)` instead. + *@legacy Use {@link Array#includes} instead. */ Object.defineProperty(Array.prototype,"contains",{ configurable:true, @@ -8732,8 +8739,12 @@ return list[0]; } }); - //!!!WARNING!!! - //Will be deprecated in next verision + /** + * @deprecated + * !!!WARNING!!! + * Will be deprecated in next verision! + * Use {@link VCard#hasNature} instead. + */ Object.defineProperty(Object.prototype,'hasNature',{ configurable:true, enumerable:false, @@ -10820,15 +10831,8 @@ } }, connection:function(ws){ - var client={ - ws:ws, - id:ws.wsid||get.id(), - closed:false - }; + const client=new lib.element.Client(ws); lib.node.clients.push(client); - for(var i in lib.element.client){ - client[i]=lib.element.client[i]; - } if(window.isNonameServer){ document.querySelector('#server_count').innerHTML=lib.node.clients.length; } @@ -20480,7 +20484,105 @@ game.delayx(); }, }, - player:{ + Player:class extends HTMLDivElement{ + /** + * @param {HTMLDivElement} [position] + * @param {true} [noclick] + */ + constructor(position,noclick){ + /** + * @type {Player} + */ + const player=ui.create.div('.player',position); + Object.setPrototypeOf(player,lib.element.Player.prototype); + const node=player.node={ + avatar:ui.create.div('.avatar',player,ui.click.avatar).hide(), + avatar2:ui.create.div('.avatar2',player,ui.click.avatar2).hide(), + turnedover:ui.create.div('.turned','
    翻面
    ',player), + framebg:ui.create.div('.framebg',player), + intro:ui.create.div('.intro',player), + identity:ui.create.div('.identity',player), + hp:ui.create.div('.hp',player), + name:ui.create.div('.name',player), + name2:ui.create.div('.name.name2',player), + nameol:ui.create.div('.nameol',player), + count:ui.create.div('.count',player).hide(), + equips:ui.create.div('.equips',player).hide(), + judges:ui.create.div('.judges',player), + marks:ui.create.div('.marks',player), + chain:ui.create.div('.chain','
    ',player), + handcards1:ui.create.div('.handcards'), + handcards2:ui.create.div('.handcards'), + expansions:ui.create.div('.expansions') + }; + node.expansions.style.display='none'; + const chainLength=game.layout=='default'?64:40; + for(let repetition=0;repetitiontarget.hp?-1:0; if(target.hasSkillTag('nogain')) return 0; return Math.max(1,get.value(card,this)-get.value(card,target)); - }, - getGiftEffect:function(card,target){ + } + getGiftEffect(card,target){ return this.getGiftAIResultTarget(card,target)*get.attitude(this,target); - }, + } //Recast //重铸 - recast:function(cards,recastingLose,recastingGain){ + recast(cards,recastingLose,recastingGain){ const recast=game.createEvent('recast'); recast.player=this; const isArray=Array.isArray(cards); @@ -20767,16 +20869,16 @@ recast.setContent('recast'); recast._args=Array.from(arguments); return recast; - }, + } //Check if the player can recast the card //检测角色是否能重铸此牌 - canRecast:function(card,source,strict){ + canRecast(card,source,strict){ return lib.filter.cardRecastable(card,this,source,strict); - }, + } //装备栏相关 //判断一名角色的某个区域是否被废除 //type为要判断的区域 若为空 则判断玩家是否有任意一个被废除的区域 - hasDisabledSlot:function(type){ + hasDisabledSlot(type){ var player=this; if(type=='horse'||type=='equip3_4'){ return player.hasDisabledSlot(3)&&(get.is.mountCombined()||player.hasDisabledSlot(4)); @@ -20785,10 +20887,10 @@ return false; } return player.countDisabledSlot(type)>0; - }, + } //判断一名角色的某个区域被废除的数量 //用法同上 - countDisabledSlot:function(type){ + countDisabledSlot(type){ var player=this; var map=(player.disabledSlots||{}); if(type==undefined){ @@ -20807,9 +20909,9 @@ if(typeof num=='number'&&num>0) return num; return 0; } - }, + } //判断一名角色是否有某个装备栏空着 - hasEmptySlot:function(type){ + hasEmptySlot(type){ var player=this; if(type=='horse'||type=='equip3_4'){ return player.hasEmptySlot(3)&&(get.is.mountCombined()||player.hasEmptySlot(4)); @@ -20818,9 +20920,9 @@ return false; } return player.countEmptySlot(type)>0; - }, + } //判断一名角色的某个装备栏空位的数量 - countEmptySlot:function(type){ + countEmptySlot(type){ if(!type) return 0; var player=this; if(typeof type=='number') type=('equip'+type); @@ -20831,15 +20933,15 @@ var types=get.subtypes(card,false); return num+get.numOf(types,type); },0)) - }, + } //判断一名角色是否有可以用于装备新装备牌的区域(排除金箍棒和六龙等“不可被替换装备”) //用法同下 - hasEquipableSlot:function(type){ + hasEquipableSlot(type){ return this.countEquipableSlot(type)>0; - }, + } //统计一名角色有多少个可以用于装备新的装备牌的区域 //用法同下 - countEquipableSlot:function(type){ + countEquipableSlot(type){ if(!type) return 0; var player=this; if(typeof type=='number') type=('equip'+type); @@ -20854,10 +20956,10 @@ if(!lib.filter.canBeReplaced(card,player)) num+=get.numOf(types,type); return num; },0)) - }, + } //判断一名角色是否拥有未被废除的某个区域 //type为要判断的区域 若为空 则判断玩家是否有任意一个未被废除的区域 - hasEnabledSlot:function(type){ + hasEnabledSlot(type){ var player=this; if(type=='horse'||type=='equip3_4'){ return player.hasEnabledSlot(3)&&(get.is.mountCombined()||player.hasEnabledSlot(4)); @@ -20869,10 +20971,10 @@ return false; } return player.countEnabledSlot(type)>0; - }, + } //判断一名角色的某个区域未被废除的数量 //用法同上 - countEnabledSlot:function(type){ + countEnabledSlot(type){ var player=this; var map=(player.expandedSlots||{}); if(!type){ @@ -20893,10 +20995,10 @@ slots-=player.countDisabledSlot(type); return slots; } - }, + } //获取一名角色装备区内某种类型的装备牌 //参数可以为数字/区域字符串/实体牌/虚拟牌/牌名 - getEquips:function(subtype){ + getEquips(subtype){ var type=(typeof subtype); switch(type){ case 'string': @@ -20926,10 +21028,10 @@ return this.getCards('e',function(card){ return get.subtypes(card,false).contains(subtype); }) - }, + } //新的废除装备区/恢复装备区/扩展装备区 //参数:废除来源角色(不写默认当前事件角色),废除区域(数字/区域字符串/数组,可以写多个,重复废除) - disableEquip:function(){ + disableEquip(){ var next=game.createEvent('disableEquip'); next.player=this; next.slots=[]; @@ -20960,8 +21062,8 @@ } next.setContent('disableEquip'); return next; - }, - enableEquip:function(){ + } + enableEquip(){ var next=game.createEvent('enableEquip'); next.player=this; next.slots=[]; @@ -20992,8 +21094,8 @@ } next.setContent('enableEquip'); return next; - }, - expandEquip:function(){ + } + expandEquip(){ var next=game.createEvent('expandEquip'); next.player=this; next.slots=[]; @@ -21024,13 +21126,13 @@ } next.setContent('expandEquip'); return next; - }, + } //判断判定区是否被废除 - isDisabledJudge:function(){ + isDisabledJudge(){ return Boolean(this.storage._disableJudge); - }, + } //同步显示扩展装备区状态 - $syncExpand:function(map){ + $syncExpand(map){ var player=this; if(!map){ map=(player.expandedSlots||{}); @@ -21041,9 +21143,9 @@ player.$syncExpand(map); },player,map); player.markSkill('expandedSlots'); - }, + } //同步装备区废除牌显示状态 - $syncDisable:function(map){ + $syncDisable(map){ const player=this; const suits={equip3:'+1马栏',equip4:'-1马栏',equip6:'特殊栏'}; if(get.is.mountCombined()) suits.equip3='坐骑栏'; @@ -21102,9 +21204,9 @@ } } } - }, + } //以下函数涉及到本次更新内容而进行修改 - canEquip:function(name,replace){ + canEquip(name,replace){ const ranges=get.subtypes(name),rangex=[],player=this,combined=get.is.mountCombined(); if(combined){ ranges.forEach(type=>{ @@ -21122,22 +21224,22 @@ if(numthis.getEquips(num).length; - }, + } //以下函数将被废弃 - $disableEquip:function(){}, - $enableEquip:function(){}, + $disableEquip(){} + $enableEquip(){} //装备区End - chooseToDebate:function(){ + chooseToDebate(){ var next=game.createEvent('chooseToDebate'); next.player=this; next._args=[]; @@ -21151,8 +21253,8 @@ } next.setContent('chooseToDebate'); return next; - }, - cooperationWith:function(target,type,reason){ + } + cooperationWith(target,type,reason){ var player=this; if(!player.storage.cooperation) player.storage.cooperation=[]; var info={ @@ -21164,8 +21266,8 @@ player.addTempSkill('cooperation',{player:'dieAfter'}); player.addSkill('cooperation_'+type,{player:'dieAfter'}); game.log(player,'向',target,'发起了“协力”,合作类型是','#g'+get.translation('cooperation_'+type)); - }, - chooseCooperationFor:function(){ + } + chooseCooperationFor(){ var next=game.createEvent('chooseCooperationFor'); next.player=this; for(var i=0;i'; - lib.element.player.say.call(this,str); + this.say(str); game.broadcast(function(id,str){ if(lib.playerOL[id]){ lib.playerOL[id].say(str); @@ -22263,16 +22365,16 @@ else if(game.connectPlayers){ for(var i=0;i=this.maxHp) this.hp=this.maxHp; game.broadcast(function(player,hp,maxHp,hujia){ @@ -22517,8 +22619,8 @@ player.$update(); },this,this.hp,this.maxHp,this.hujia); this.$update(); - }, - $update:function(){ + } + $update(){ if(this.hp>=this.maxHp) this.hp=this.maxHp; var hp=this.node.hp; hp.style.transition='none'; @@ -22625,8 +22727,8 @@ this.node.count.innerHTML=numh; } if(this.updates){ - for(var i=0;i0) this.removeMark(i,num,log) - }, - removeMark:function(i,num,log){ + } + removeMark(i,num,log){ if(typeof num!='number'||!num) num=1; if(typeof this.storage[i]!='number'||!this.storage[i]) return; if(num>this.storage[i]) num=this.storage[i]; @@ -22653,8 +22755,8 @@ } this.syncStorage(i); this[(this.storage[i]||(lib.skill[i]&&lib.skill[i].mark))?'markSkill':'unmarkSkill'](i); - }, - addMark:function(i,num,log){ + } + addMark(i,num,log){ if(typeof num!='number'||!num) num=1; if(typeof this.storage[i]!='number') this.storage[i]=0; this.storage[i]+=num; @@ -22667,22 +22769,22 @@ } this.syncStorage(i); this.markSkill(i); - }, - setMark:function(name,num,log){ + } + setMark(name,num,log){ const count=this.countMark(name); if(count>num)this.removeMark(name,count-num,log); else if(count0; - }, - updateMark:function(i,storage){ + } + updateMark(i,storage){ if(!this.marks[i]){ if(lib.skill[i]&&lib.skill[i].intro&&(this.storage[i]||lib.skill[i].intro.markcount)){ this.markSkill(i); @@ -22739,8 +22841,8 @@ } } return this; - }, - updateMarks:function(connect){ + } + updateMarks(connect){ if(typeof connect=='string'&&_status.connectMode&&!game.online){ game.broadcast(function(player,storage,skill){ player.storage[skill]=storage; @@ -22750,8 +22852,8 @@ for(var i in this.marks){ this.updateMark(i); } - }, - num:function(arg1,arg2,arg3){ + } + num(arg1,arg2,arg3){ if(get.itemtype(arg1)=='position'){ return this.get(arg1,arg2,arg3).length; } @@ -22763,8 +22865,8 @@ return game.expandSkills(this.getSkills().concat(lib.skill.global)).contains(arg2); } } - }, - line:function(target,config){ + } + line(target,config){ if(get.itemtype(target)=='players'){ for(var i=0;i0||this.isDying()) return; var next=game.createEvent('dying'); next.player=this; @@ -25382,16 +25484,16 @@ } }; return next; - }, - die:function(reason){ + } + die(reason){ var next=game.createEvent('die'); next.player=this; next.reason=reason; if(reason) next.source=reason.source; next.setContent('die'); return next; - }, - revive:function(hp,log){ + } + revive(hp,log){ if(log!==false) game.log(this,'复活'); if(this.maxHp<1) this.maxHp=1; if(hp) this.hp=hp; @@ -25442,11 +25544,11 @@ delete ui.continue_game; } } - }, - isMad:function(){ + } + isMad(){ return this.hasSkill('mad'); - }, - goMad:function(end){ + } + goMad(end){ if(end){ this.addTempSkill('mad',end); } @@ -25454,14 +25556,14 @@ this.addSkill('mad'); } game.log(this,'进入混乱状态'); - }, - unMad:function(){ + } + unMad(){ this.removeSkill('mad'); - }, - tempHide:function(){ + } + tempHide(){ this.addTempSkill('qianxing',{player:'phaseBeginStart'}); - }, - addExpose:function(num){ + } + addExpose(num){ if(typeof this.ai.shown=='number'&&!this.identityShown&&this.ai.shown<1){ this.ai.shown+=num; if(this.ai.shown>0.95){ @@ -25469,8 +25571,8 @@ } } return this; - }, - equip:function(card,draw){ + } + equip(card,draw){ var next=game.createEvent('equip'); next.card=card; next.player=this; @@ -25522,8 +25624,8 @@ return map; }; return next; - }, - addJudge:function(card,cards){ + } + addJudge(card,cards){ var next=game.createEvent('addJudge'); if(get.itemtype(card)=='card'){ next.card=card; @@ -25581,8 +25683,8 @@ return map; }; return next; - }, - canAddJudge:function(card){ + } + canAddJudge(card){ if(this.isDisabledJudge()) return false; var name; if(typeof card=='string'){ @@ -25597,8 +25699,8 @@ var mod=game.checkMod(card,this,this,'unchanged','targetEnabled',this); if(mod!='unchanged') return mod; return true; - }, - addJudgeNext:function(card,unlimited){ + } + addJudgeNext(card,unlimited){ if(!card.expired){ let target=this.next; const name=card.viewAs||card.name; @@ -25633,8 +25735,8 @@ else{ card.expired=false; } - }, - judge:function(){ + } + judge(){ var next=game.createEvent('judge'); next.player=this; for(var i=0;i0?'markSkill':'unmarkSkill'](name); } } - }, - unmarkAuto:function(name,info){ + } + unmarkAuto(name,info){ var storage=this.storage[name] if(Array.isArray(info)&&Array.isArray(storage)){ storage.removeArray(info.slice(0)); this.markAuto(name); } - }, - getExpansions:function(tag){ + } + getExpansions(tag){ return this.getCards('x',(card)=>card.hasGaintag(tag)); - }, - countExpansions:function(tag){ + } + countExpansions(tag){ return this.getExpansions(tag).length; - }, - hasExpansions:function(tag){ + } + hasExpansions(tag){ return this.countExpansions(tag)>0; - }, - setStorage:function(name,value,mark){ + } + setStorage(name,value,mark){ this.storage[name]=value; if(mark) this.markAuto(name); return value; - }, - getStorage:function(name){ + } + getStorage(name){ return this.storage[name]||[]; - }, - hasStorage:function(name,value){ + } + hasStorage(name,value){ if(!(name in this.storage)) return false; if(typeof value=="undefined") return true; const storage=this.storage[name]; if(storage===value) return true; return Array.isArray(storage) && storage.includes(value); - }, - hasStorageAny:function(name,values){ + } + hasStorageAny(name,values){ const storage=this.storage[name]; if(!Array.isArray(values)) values=Array.from(arguments).slice(1); if(!storage) return false; if (!Array.isArray(storage)) return values.contains(storage); return values.some(item => storage.contains(item)); - }, - hasStorageAll:function(name,values){ + } + hasStorageAll(name,values){ const storage=this.storage[name]; if(!Array.isArray(values)) values=Array.from(arguments).slice(1); if(!storage) return false; if (!Array.isArray(storage)) return false; return values.every(item => storage.contains(item)); - }, - initStorage:function(name,value,mark){ + } + initStorage(name,value,mark){ return this.hasStorage(name)?this.getStorage(name):this.setStorage(name,value,mark); - }, - updateStorage:function(name,operation,mark){ + } + updateStorage(name,operation,mark){ return this.setStorage(name,operation(this.getStorage(name)),mark); - }, - updateStorageAsync:function(name,operation,mark){ + } + updateStorageAsync(name,operation,mark){ return Promise.resolve(this.getStorage(name)) .then(value=>operation(value)) .then(value=>this.setStorage(name,value,mark)); - }, - removeStorage:function(name,mark){ + } + removeStorage(name,mark){ if(!this.hasStorage(name)) return false; delete this.storage[name] if(mark){ this.unmarkSkill(name); } return true; - }, - markSkill:function(name,info,card,nobroadcast){ + } + markSkill(name,info,card,nobroadcast){ if(info===true){ this.syncStorage(name); info=null; @@ -26225,8 +26327,8 @@ func(this.storage[name],this,name,info,card); if(!nobroadcast) game.broadcast(func,this.storage[name],this,name,info,card); return this; - }, - unmarkSkill:function(name,nobroadcast){ + } + unmarkSkill(name,nobroadcast){ game.addVideo('unmarkSkill',this,name); if(!nobroadcast) game.broadcast(function(player,name){ if(player.marks[name]){ @@ -26258,8 +26360,8 @@ } } return this; - }, - markSkillCharacter:function(id,target,name,content,nobroadcast){ + } + markSkillCharacter(id,target,name,content,nobroadcast){ if(typeof target=='object'){ target=target.name; } @@ -26298,8 +26400,8 @@ func(this,target,name,content,id); if(!nobroadcast) game.broadcast(func,this,target,name,content,id); return this; - }, - markCharacter:function(name,info,learn,learn2){ + } + markCharacter(name,info,learn,learn2){ if(typeof name=='object'){ name=name.name; } @@ -26335,8 +26437,8 @@ } ui.updatem(this); return node; - }, - mark:function(name,info,skill){ + } + mark(name,info,skill){ if(get.itemtype(name)=='cards'){ var marks=[]; for(var i=0;i0; - }, - getUseValue:function(card,distance,includecard){ + } + getUseValue(card,distance,includecard){ if(typeof(card)=='string'){ card={name:card,isCard:true}; } @@ -26500,8 +26602,8 @@ min+=value[i]; } return min; - }, - addSubPlayer:function(cfg){ + } + addSubPlayer(cfg){ var skill='subplayer_'+cfg.name+'_'+get.id(); game.log(this,'获得了随从','#g'+get.translation(cfg.name)) cfg.hs=cfg.hs||[]; @@ -26539,8 +26641,8 @@ game.addVideo('addSubPlayer',this,[skill,lib.skill[skill],lib.character[skill],lib.translate[skill],{name:cfg.name}]); this.addSkill(skill); return skill; - }, - removeSubPlayer:function(name){ + } + removeSubPlayer(name){ if(this.hasSkill('subplayer')&&this.name==name){ this.exitSubPlayer(true); } @@ -26553,8 +26655,8 @@ game.log(player,'牺牲了随从','#g'+name); _status.event.trigger('removeSubPlayer'); } - }, - callSubPlayer:function(){ + } + callSubPlayer(){ if(this.hasSkill('subplayer')) return; var next=game.createEvent('callSubPlayer'); next.player=this; @@ -26565,8 +26667,8 @@ } next.setContent('callSubPlayer'); return next; - }, - toggleSubPlayer:function(){ + } + toggleSubPlayer(){ if(!this.hasSkill('subplayer')) return; var next=game.createEvent('toggleSubPlayer'); next.player=this; @@ -26577,16 +26679,16 @@ } next.setContent('toggleSubPlayer'); return next; - }, - exitSubPlayer:function(remove){ + } + exitSubPlayer(remove){ if(!this.hasSkill('subplayer')) return; var next=game.createEvent('exitSubPlayer'); next.player=this; next.remove=remove; next.setContent('exitSubPlayer'); return next; - }, - getSubPlayers:function(tag){ + } + getSubPlayers(tag){ var skills=this.getSkills(); var list=[]; for(var i=0;i=0;i--){ if(this.actionHistory[i].isMe){ @@ -27278,8 +27380,8 @@ } return history.filter(filter); } - }, - checkAllHistory:function(key,filter,last){ + } + checkAllHistory(key,filter,last){ if(!key||!filter) return; this.actionHistory.forEach((value)=>{ let history=value[key]; @@ -27294,8 +27396,8 @@ history.forEach(filter); } }); - }, - getAllHistory:function(key,filter,last){ + } + getAllHistory(key,filter,last){ const history=[]; this.actionHistory.forEach((value)=>{ if(!key||!value[key]){ @@ -27316,8 +27418,8 @@ return history.filter(filter); } return history; - }, - hasAllHistory:function(key,filter,last){ + } + hasAllHistory(key,filter,last){ return this.actionHistory.some((value)=>{ let history=value[key]; if(last&&history.includes(last)){ @@ -27332,18 +27434,18 @@ } return false; }) - }, - getLastUsed:function(num){ + } + getLastUsed(num){ if(typeof num!='number') num=0; var history=this.getHistory('useCard'); if(history.length<=num) return null; return history[history.length-num-1]; - }, - getStat:function(key){ + } + getStat(key){ if(!key) return this.stat[this.stat.length-1]; return this.stat[this.stat.length-1][key]; - }, - getLastStat:function(key){ + } + getLastStat(key){ var stat=false; for(var i=this.stat.length-1;i>=0;i--){ if(this.stat[i].isMe){ @@ -27353,8 +27455,8 @@ if(!stat) return null if(!key) return stat; return stat[key]; - }, - queue:function(time){ + } + queue(time){ if(time==false){ clearTimeout(this.queueTimeout); this.queueCount=0; @@ -27375,8 +27477,8 @@ if(player==game.me) ui.me.removeAttribute('style'); } },time) - }, - getCardUsable:function(card,pure){ + } + getCardUsable(card,pure){ var player=this; if(typeof card=='string'){ card={name:card}; @@ -27390,8 +27492,8 @@ return num-player.countUsed(card); } return num; - }, - getAttackRange:function(raw){ + } + getAttackRange(raw){ const player=this; let range=0; if(raw){ @@ -27417,8 +27519,8 @@ } range=game.checkMod(player,range,'attackRange',player); return range; - }, - getEquipRange:function(cards){ + } + getEquipRange(cards){ const player=this; if(!cards) cards=player.getCards('e',function(card){ return !ui.selected.cards||!ui.selected.cards.contains(card); @@ -27442,8 +27544,8 @@ else return (isN1?range:newRange); },false); return (typeof range=='number')?range:1; - }, - getGlobalFrom:function(){ + } + getGlobalFrom(){ var player=this; var range=0; range=game.checkMod(player,player,range,'globalFrom',player); @@ -27458,8 +27560,8 @@ } } return (-range); - }, - getGlobalTo:function(){ + } + getGlobalTo(){ var player=this; var range=0; range=game.checkMod(player,player,range,'globalTo',player); @@ -27474,15 +27576,15 @@ } } return (range); - }, - getHandcardLimit:function(){ + } + getHandcardLimit(){ var num=Math.max(this.hp,0); num=game.checkMod(this,num,'maxHandcardBase',this); num=game.checkMod(this,num,'maxHandcard',this); num=game.checkMod(this,num,'maxHandcardFinal',this); return Math.max(0,num); - }, - getEnemies:function(func){ + } + getEnemies(func){ var player=this; var targets; var mode=get.mode(); @@ -27553,8 +27655,8 @@ } targets.remove(player); return targets; - }, - getFriends:function(func){ + } + getFriends(func){ var player=this; var targets; var mode=get.mode(); @@ -27625,11 +27727,11 @@ targets.remove(player); } return targets; - }, - isEnemyOf:function(){ + } + isEnemyOf(){ return !this.isFriendOf.apply(this,arguments); - }, - isFriendOf:function(player){ + } + isFriendOf(player){ if(get.mode()=='guozhan'){ if(this==player) return true; if(this.getStorage('yexinjia_friend').includes(player)||player.getStorage('yexinjia_friend').includes(this)) return true; @@ -27644,111 +27746,111 @@ return this.side==player.side; } return this==player; - }, - isFriendsOf:function(player){ + } + isFriendsOf(player){ return player.getFriends(true).contains(this); - }, - isEnemiesOf:function(player){ + } + isEnemiesOf(player){ return player.getEnemies().contains(this); - }, - isAlive:function(){ + } + isAlive(){ return this.classList.contains('dead')==false; - }, - isDead:function(){ + } + isDead(){ return this.classList.contains('dead'); - }, - isDying:function(){ + } + isDying(){ return _status.dying.contains(this)&&this.hp<=0&&this.isAlive(); - }, - isDamaged:function(){ + } + isDamaged(){ return this.hp=this.maxHp||this.storage.nohp; - }, - isMaxHp:function(only,raw){ + } + isMaxHp(only,raw){ return game.players.every(value=>{ if(value.isOut()||value==this) return true; return only?value.getHp(raw){ if(value.isOut()||value==this) return true; return only?value.getHp(raw)>this.getHp(raw):value.getHp(raw)>=this.getHp(raw); }); - }, - isMaxCard:function(only){ + } + isMaxCard(only){ const numberOfCards=this.countCards('he'); return game.players.every(value=>{ if(value.isOut()||value==this) return true; return only?value.countCards('he'){ if(value.isOut()||value==this) return true; return only?value.countCards('he')>numberOfCards:value.countCards('he')>=numberOfCards; }); - }, - isMaxHandcard:function(only){ + } + isMaxHandcard(only){ const numberOfHandCards=this.countCards('h'); return game.players.every(value=>{ if(value.isOut()||value==this) return true; return only?value.countCards('h'){ if(value.isOut()||value==this) return true; return only?value.countCards('h')>numberOfHandCards:value.countCards('h')>=numberOfHandCards; }); - }, - isMaxEquip:function(only){ + } + isMaxEquip(only){ const numberOfEquipAreaCards=this.countCards('e'); return game.players.every(value=>{ if(value.isOut()||value==this) return true; return only?value.countCards('e'){ if(value.isOut()||value==this) return true; return only?value.countCards('e')>numberOfEquipAreaCards:value.countCards('e')>=numberOfEquipAreaCards; }); - }, - isLinked:function(){ + } + isLinked(){ if(get.is.linked2(this)){ return this.classList.contains('linked2'); } return this.classList.contains('linked'); - }, - isTurnedOver:function(){ + } + isTurnedOver(){ return this.classList.contains('turnedover'); - }, - isOut:function(){ + } + isOut(){ return this.classList.contains('out'); - }, - isMin:function(distance){ + } + isMin(distance){ if(distance&&lib.config.mode!='stone') return false; if(this.forcemin) return true; return this.classList.contains('minskin')&&!game.chess; - }, - isIn:function(){ + } + isIn(){ return this.classList.contains('dead')==false&&this.classList.contains('out')==false&&!this.removed; - }, - isUnseen:function(num){ + } + isUnseen(num){ switch(num){ case 0:return this.classList.contains('unseen'); case 1:return this.classList.contains('unseen2'); case 2:return this.classList.contains('unseen')||this.classList.contains('unseen2'); default:return this.classList.contains('unseen')&&(!this.name2||this.classList.contains('unseen2')); } - }, - isUnderControl:function(self,me){ + } + isUnderControl(self,me){ me=(me||game.me); var that=this._trueMe||this; if(that.isMad()||game.notMe) return false; @@ -27776,26 +27878,26 @@ return this.side==me.side; } return false; - }, - isOnline:function(){ + } + isOnline(){ if(this.ws&&lib.node&&!this.ws.closed&&this.ws.inited&&!this.isAuto){ return true; } return false; - }, - isOnline2:function(){ + } + isOnline2(){ if(this.ws&&lib.node&&!this.ws.closed){ return true; } return false; - }, - isOffline:function(){ + } + isOffline(){ if(this.ws&&lib.node&&this.ws.closed){ return true; } return false; - }, - checkShow:function(skill,showonly){ + } + checkShow(skill,showonly){ var sourceSkill=get.info(skill); var noshow=false; if(sourceSkill&&sourceSkill.sourceSkill){ @@ -27829,24 +27931,24 @@ } } return false; - }, - needsToDiscard:function(num){ + } + needsToDiscard(num){ if(typeof num!='number') num=0; return Math.max(0,num+this.countCards('h',card=>!this.canIgnoreHandcard(card))-this.getHandcardLimit()); - }, - distanceTo:function(target,method){ + } + distanceTo(target,method){ return get.distance(this,target,method); - }, - distanceFrom:function(target,method){ + } + distanceFrom(target,method){ return get.distance(target,this,method); - }, - hasSkill:function(skill,arg2,arg3,arg4){ + } + hasSkill(skill,arg2,arg3,arg4){ return game.expandSkills(this.getSkills(arg2,arg3,arg4)).contains(skill); - }, - hasStockSkill:function(skill,arg1,arg2,arg3){ + } + hasStockSkill(skill,arg1,arg2,arg3){ return game.expandSkills(this.getStockSkills(arg1,arg2,arg3)).contains(skill); - }, - isZhu2:function(){ + } + isZhu2(){ var player=this,mode=get.mode(); if(!this.isZhu) return false; if(mode=='identity'){ @@ -27855,8 +27957,8 @@ } if(mode=='versus'&&(_status.mode=='four'||_status.mode=='guandu')) return true; return false; - }, - hasZhuSkill:function(skill,player){ + } + hasZhuSkill(skill,player){ if(!this.hasSkill(skill)) return false; if(player){ var mode=get.mode(); @@ -27868,8 +27970,8 @@ } } return true; - }, - hasGlobalTag:function(tag,arg){ + } + hasGlobalTag(tag,arg){ var skills=lib.skill.global.slice(0); game.expandSkills(skills); for(var i=0;i0){ @@ -27928,8 +28030,8 @@ } } return false; - }, - hasUnknown:function(num){ + } + hasUnknown(num){ var mode=get.mode(); if(typeof num!='number'){ num=0; @@ -27945,8 +28047,8 @@ } } return false; - }, - isUnknown:function(player){ + } + isUnknown(player){ var mode=get.mode(); if(mode=='identity'||mode=='guozhan'){ if(this.ai.shown==0&&this!=player){ @@ -27954,8 +28056,8 @@ } } return false; - }, - hasWuxie:function(info){ + } + hasWuxie(info){ if(this.countCards('hs','wuxie')) return true; var skills=this.getSkills('invisible').concat(lib.skill.global); game.expandSkills(skills); @@ -27979,21 +28081,21 @@ } } return false; - }, - hasSha:function(respond,noauto){ + } + hasSha(respond,noauto){ if(this.countCards('hs','sha')) return true; if(this.countCards('hs','hufu')) return true; if(!noauto&&this.countCards('hs','yuchanqian')) return true; if(this.hasSkillTag('respondSha',true,respond?'respond':'use',true)) return true; return this.hasUsableCard('sha'); - }, - hasShan:function(){ + } + hasShan(){ if(this.countCards('hs','shan')) return true; if(this.countCards('hs','hufu')) return true; if(this.hasSkillTag('respondShan',true,null,true)) return true; return this.hasUsableCard('shan'); - }, - mayHaveSha:function(viewer,type){ + } + mayHaveSha(viewer,type){ if((this.hp>2||!this.isZhu&&this.hp>1)&&this.hasSkillTag('respondSha',true,type,true)) return true; if(get.itemtype(viewer)!=='player') viewer=_status.event.player; let cards; @@ -28011,8 +28113,8 @@ let hs=this.getCards('hs').removeArray(cards).length; if(hs===0) return false; return Math.pow(hs+(this.isPhaseUsing()?6:4),2)>100*_status.event.getRand('mayHaveSha'); - }, - mayHaveShan:function(viewer,type){ + } + mayHaveShan(viewer,type){ if((this.hp>2||!this.isZhu&&this.hp>1)&&this.hasSkillTag('respondShan',true,type,true)) return true; if(get.itemtype(viewer)!=='player') viewer=_status.event.player; let cards; @@ -28030,8 +28132,8 @@ let hs=this.getCards('hs').removeArray(cards).length; if(hs===0) return false; return Math.pow(hs+(this.isPhaseUsing()?3:5),2)>100*_status.event.getRand('mayHaveShan'); - }, - hasCard:function(name,position){ + } + hasCard(name,position){ if(typeof name=='function'){ var hs=this.getCards(position); for(var i=0;i} + */ + this.storage=get.copy(suitOrCard.storage); + if(Array.isArray(numberOrCards)) this.cards=numberOrCards.slice(); + else this.cards=[suitOrCard]; + const info=get.info(this,false); + if(info){ + const autoViewAs=info.autoViewAs; + if(typeof autoViewAs=='string') this.name=autoViewAs; + } + } + else if(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'); + /** + * @type {Card[]} + */ + this.cards=numberOrCards.slice(); + if(noCards){ + if(!lib.suits.includes(this.suit)) this.suit=get.suit(this); + if(!Object.keys(lib.color).includes(this.color)) this.color=get.color(this); + if(!this.hasOwnProperty('number')) this.number=get.number(this); + if(!this.hasOwnProperty('nature')) this.nature=get.nature(this); + } + } + const info=get.info(this,false); + if(info){ + const autoViewAs=info.autoViewAs; + if(typeof autoViewAs=='string') this.name=autoViewAs; + } + } + if(typeof suitOrCard=='string') this.suit=suitOrCard; + if(typeof numberOrCards=='number') this.number=numberOrCards; + if(typeof name=='string') this.name=name; + if(typeof nature=='string') this.nature=nature; + if(this.hasOwnProperty('suit')&&!this.hasOwnProperty('color')) this.color=get.color(this); + if(!this.hasOwnProperty('storage')) this.storage={}; + if(!this.hasOwnProperty('cards')) this.cards=[]; + } + /** + * @param {Player} player + */ + hasNature(nature,player){ + const natures=get.natureList(this,player); + if(!nature) return natures.length>0; + if(nature=='linked') return natures.some(n=>lib.linked.includes(n)); + return get.is.sameNature(natures,nature); + } + }, + Button:class extends HTMLDivElement{ + /** + * @param {{}} item + * @param {keyof typeof ui.create.buttonPresets | (item: {}, type: Function, position?: HTMLDivElement, noClick?: true, button?: HTMLDivElement) => HTMLDivElement} type + * @param {HTMLDivElement} [position] + * @param {true} [noClick] + * @param {HTMLDivElement} [button] + */ + constructor(item,type,position,noClick,button){ + if(ui.create.buttonPresets[type]) button=ui.create.buttonPresets[type](item,type,position,noClick,button); + else if(typeof type=='function') button=type(item,type,position,noClick,button); + Object.setPrototypeOf(button,lib.element.Button.prototype); + if(!noClick) button.addEventListener(lib.config.touchscreen?'touchend':'click',ui.click.button); + else{ + button.classList.add('noclick'); + const intro=button.querySelector('.intro'); + if(intro) intro.remove(); + } + return button; + } + exclude(){ if(_status.event.excludeButton==undefined){ _status.event.excludeButton=[]; } _status.event.excludeButton.add(this); } }, - event:{ - changeToZero:function(){ + Event:class{ + /** + * @param {string} [name] + * @param {false} [trigger] + */ + constructor(name,trigger){ + this.name=name; + this.step=0; + this.finished=false; + /** + * @type {this[]} + */ + this.next=[]; + /** + * @type {this[]} + */ + this.after=[]; + this.custom={ + add:{}, + replace:{} + }; + this._aiexclude=[]; + this._notrigger=[]; + this._result={}; + this._set=[]; + if(trigger!==false&&!game.online) this._triggered=0; + } + changeToZero(){ this.num=0; this.numFixed=true; - }, - finish:function(){ + return this; + } + finish(){ this.finished=true; - }, - putStepCache:function(key,value){ + return this; + } + putStepCache(key,value){ if(!this._stepCache){ - this._stepCache = {}; + this._stepCache={}; } - this._stepCache[key] = value; - }, - getStepCache:function(key){ - if(!this._stepCache)return undefined; + this._stepCache[key]=value; + return this; + } + getStepCache(key){ + if(!this._stepCache) return undefined; return this._stepCache[key]; - }, - clearStepCache:function(key){ - if(key !== undefined && key !== null){ + } + clearStepCache(key){ + if(key!==undefined&&key!==null){ delete this._stepCache[key]; } delete this._stepCache; - }, - callFuncUseStepCache:function(prefix,func,params){ - if(typeof func != 'function')return; - if(_status.closeStepCache)return func.apply(null,params); - var cacheKey = "["+prefix+"]"+get.paramToCacheKey.apply(null,params); - var ret = this.getStepCache(cacheKey); - if(ret === undefined || ret === null){ - ret = func.apply(null,params); + return this; + } + callFuncUseStepCache(prefix,func,params){ + if(typeof func!='function') return; + if(_status.closeStepCache) return func.apply(null,params); + var cacheKey="["+prefix+"]"+get.paramToCacheKey.apply(null,params); + var ret=this.getStepCache(cacheKey); + if(ret===undefined||ret===null){ + ret=func.apply(null,params); this.putStepCache(cacheKey,ret); } return ret; - }, - putTempCache:function(key1,key2,value){ + } + putTempCache(key1,key2,value){ if(!this._tempCache){ - this._tempCache = {}; + this._tempCache={}; } if(!this._tempCache[key1]){ - this._tempCache[key1] = {}; + this._tempCache[key1]={}; } - this._tempCache[key1][key2] = value; + this._tempCache[key1][key2]=value; return value; - }, - getTempCache:function(key1,key2){ + } + getTempCache(key1,key2){ if(!this._tempCache){ return undefined; } @@ -30246,41 +30532,47 @@ return undefined; } return this._tempCache[key1][key2]; - }, - cancel:function(arg1,arg2,notrigger){ + } + cancel(arg1,arg2,notrigger){ this.untrigger(arg1,arg2); this.finish(); if(notrigger!='notrigger'){ this.trigger(this.name+'Cancelled'); - if(this.player&&lib.phaseName.contains(this.name)) this.player.getHistory('skipped').add(this.name)} - }, - neutralize:function(event){ + if(this.player&&lib.phaseName.contains(this.name)) this.player.getHistory('skipped').add(this.name); + } + return this; + } + neutralize(event){ this.untrigger(); this.finish(); this._neutralized=true; this.trigger('eventNeutralized'); this._neutralize_event=event||_status.event; - }, - unneutralize:function(){ + return this; + } + unneutralize(){ this.untrigger(); delete this._neutralized; delete this.finished; if(this.type=='card'&&this.card&&this.name=='sha') this.directHit=true; - }, - goto:function(step){ + return this; + } + goto(step){ this.step=step-1; - }, - redo:function(){ + return this; + } + redo(){ this.step--; - }, - setHiddenSkill:function(skill){ + return this; + } + setHiddenSkill(skill){ if(!this.player) return this; var hidden=this.player.hiddenSkills.slice(0); game.expandSkills(hidden); if(hidden.contains(skill)) this.set('hsskill',skill); return this; - }, - set:function(key,value){ + } + set(key,value){ if(arguments.length==1&&Array.isArray(arguments[0])){ for(var i=0;inext.set(entry[0],entry[1])); return next; - }, - insertAfter:function(func,map){ - var next=game.createEvent(this.name+'Inserted',false,{next:[]}); + } + insertAfter(content,map){ + const next=new lib.element.Event(`${this.name}Inserted`,false); this.after.push(next); - next.setContent(func); - for(var i in map){ - next.set(i,map[i]); - } + next.setContent(content); + Object.entries(map).forEach(entry=>next.set(entry[0],entry[1])); return next; - }, - backup:function(skill){ + } + backup(skill){ this._backup={ filterButton:this.filterButton, selectButton:this.selectButton, @@ -30533,8 +30824,9 @@ delete this._cardChoice; delete this._targetChoice; delete this._skillChoice; - }, - restore:function(){ + return this; + } + restore(){ if(this._backup){ this.filterButton=this._backup.filterButton; this.selectButton=this._backup.selectButton; @@ -30559,29 +30851,30 @@ delete this.skill; delete this.ignoreMod; delete this.filterCard2; - }, - isMine:function(){ + return this; + } + isMine(){ return (this.player&&this.player==game.me&&!_status.auto&&!this.player.isMad()&&!game.notMe); - }, - isOnline:function(){ + } + isOnline(){ return (this.player&&this.player.isOnline()); - }, - notLink:function(){ + } + notLink(){ return this.getParent().name!='_lianhuan'&&this.getParent().name!='_lianhuan2'; - }, - isPhaseUsing:function(player){ + } + isPhaseUsing(player){ var evt=this.getParent('phaseUse'); if(!evt||evt.name!='phaseUse') return false; return !player||player==evt.player; - }, - addTrigger:function(skill,player){ - if(!player||!skill) return; + } + addTrigger(skill,player){ + if(!player||!skill) return this; var evt=this; if(typeof skill=='string') skill=[skill]; game.expandSkills(skill); while(true){ var evt=evt.getParent('arrangeTrigger'); - if(!evt||evt.name!='arrangeTrigger'||!evt.map) return; + if(!evt||evt.name!='arrangeTrigger'||!evt.map) return this; var filter=function(content){ if(typeof content=='string') return content==triggername; return content.contains(triggername); @@ -30595,7 +30888,7 @@ if(evt.map[i].player==player){map=evt.map[i];break;} } } - if(!map) return; + if(!map) return this; var func=function(skillx){ var info=lib.skill[skillx]; var bool=false; @@ -30622,8 +30915,9 @@ func(skill[j]); } } - }, - removeTrigger:function(skill,player){ + return this; + } + removeTrigger(skill,player){ if(!player||!skill) return; var evt=this; if(typeof skill=='string') skill=[skill]; @@ -30658,10 +30952,46 @@ func(skill[j]); } } - }, - trigger:function(name){ - if(_status.video) return; - if((this.name==='gain'||this.name==='lose')&&!_status.gameDrawed) return; + } + removeTrigger(skill,player){ + if(!player||!skill) return; + var evt=this; + if(typeof skill=='string') skill=[skill]; + game.expandSkills(skill); + while(true){ + var evt=evt.getParent('arrangeTrigger'); + if(!evt||evt.name!='arrangeTrigger'||!evt.map) return; + var filter=function(content){ + if(typeof content=='string') return content==triggername; + return content.contains(triggername); + }; + var trigger=evt._trigger; + var triggername=evt.triggername; + var map=false; + if(evt.doing&&evt.doing.player==player) map=evt.doing; + else{ + for(var i=0;i{ + return i[0]==skillx&&i[1]==player; + }); + if(toremove.length>0) map.list.removeArray(toremove); + } + for(var j=0;j
    '); @@ -30937,19 +31302,19 @@ this.add('
    '+str+'
    '); } return this; - }, - addSmall:function(item,noclick){ + } + addSmall(item,noclick){ return this.add(item,noclick,true); - }, - addAuto:function(content){ + } + addAuto(content){ if(content&&content.length>4&&!this._hovercustomed){ this.addSmall(content); } else{ this.add(content); } - }, - open:function(){ + } + open(){ if(this.noopen) return; for(var i=0;i0){ @@ -31005,14 +31370,58 @@ // ui.arenalog.classList.remove('withdialog'); // } return this; - }, - setCaption:function(str){ + } + setCaption(str){ this.querySelector('.caption').innerHTML=str; return this; } }, - control:{ - open:function(){ + Control:class extends HTMLDivElement{ + constructor(){ + const nc=!ui.control.querySelector('div:not(.removing):not(.stayleft)'); + const controls=Array.isArray(arguments[0])?arguments[0]:Array.from(arguments); + const control=ui.create.div('.control'); + Object.setPrototypeOf(control,lib.element.Control.prototype); + ui.control.insertBefore(control,_status.createControl||ui.confirm); + controls.forEach(argument=>{ + if(argument=='nozoom') return; + if(typeof argument=='function') control.custom=argument; + else if(argument=='stayleft'){ + control.stayleft=true; + control.classList.add('stayleft'); + } + else control.add(argument); + }); + ui.controls.unshift(control); + if(nc) ui.control.animate('nozoom',100); + if(control.childNodes.length){ + control.style.transition='opacity 0.5s'; + control.animate('controlpressdownx',500); + ui.refresh(control); + if(!control.stayleft) control.style.transform=`translateX(-${control.offsetWidth/2}px)`; + control.style.opacity=1; + ui.refresh(control); + control.style.transition=''; + } + + control.addEventListener(lib.config.touchscreen?'touchend':'click',ui.click.control2); + + if(lib.config.button_press){ + control.addEventListener(lib.config.touchscreen?'touchstart':'mousedown',function(){ + if(this.classList.contains('disabled')) return; + this.classList.add('controlpressdown'); + if(typeof this._offset=='number') this.style.transform=`translateX(${this._offset}px) scale(0.97)`; + }); + control.addEventListener(lib.config.touchscreen?'touchend':'mouseup',function(){ + this.classList.remove('controlpressdown'); + if(typeof this._offset=='number') this.style.transform=`translateX(${this._offset}px)`; + }); + } + + ui.updatec(); + return control; + } + open(){ ui.control.insertBefore(this,_status.createControl||ui.confirm); ui.controls.unshift(this); if(this.childNodes.length){ @@ -31028,15 +31437,15 @@ } ui.updatec(); return this; - }, - add:function(item){ + } + add(item){ var node=document.createElement('div'); this.appendChild(node); node.link=item; node.innerHTML=get.translation(item); node.addEventListener(lib.config.touchscreen?'touchend':'click',ui.click.control); - }, - close:function(){ + } + close(){ this.animate('controlpressdownx',500); ui.controls.remove(this); @@ -31049,8 +31458,8 @@ if(ui.skills==this) delete ui.skills; if(ui.skills2==this) delete ui.skills2; if(ui.skills3==this) delete ui.skills3; - }, - replace:function(){ + } + replace(){ // this.animate('controlpressdownx',500); if(this.replaceTransition===false){ this.style.transitionProperty='none'; @@ -31086,8 +31495,16 @@ return this; } }, - client:{ - send:function(){ + Client:class{ + /** + * @param {NodeWS | InstanceType} ws + */ + constructor(ws){ + this.ws=ws; + this.id=ws.wsid||get.id(); + this.closed=false; + } + send(){ if(this.closed) return this; var args=Array.from(arguments); if(typeof args[0]=='function'){ @@ -31103,8 +31520,8 @@ this.ws.close(); } return this; - }, - close:function(){ + } + close(){ lib.node.clients.remove(this); lib.node.observing.remove(this); if(ui.removeObserve&&!lib.node.observing.length){ @@ -31139,14 +31556,20 @@ return this; } }, - nodews:{ - send:function(message){ + NodeWS:class{ + /** + * @param {string} id + */ + constructor(id){ + this.wsid=id; + } + send(message){ game.send('server','send',this.wsid,message); - }, - on:function(type,func){ + } + on(type,func){ this['on'+type]=func; - }, - close:function(){ + } + close(){ game.send('server','close',this.wsid); } }, @@ -31211,6 +31634,54 @@ game.online=false; game.ws=null; } + }, + /** + * @legacy Use {@link lib.element.Player.prototype} instead. + */ + get player(){ + return this.Player.prototype; + }, + /** + * @legacy Use {@link lib.element.Card.prototype} instead. + */ + get card(){ + return this.Card.prototype; + }, + /** + * @legacy Use {@link lib.element.Button.prototype} instead. + */ + get button(){ + return this.Button.prototype; + }, + /** + * @legacy Use {@link lib.element.Event.prototype} instead. + */ + get event(){ + return this.Event.prototype; + }, + /** + * @legacy Use {@link lib.element.Dialog.prototype} instead. + */ + get dialog(){ + return this.Dialog.prototype; + }, + /** + * @legacy Use {@link lib.element.Control.prototype} instead. + */ + get control(){ + return this.Control.prototype; + }, + /** + * @legacy Use {@link lib.element.Client.prototype} instead. + */ + get client(){ + return this.Client.prototype; + }, + /** + * @legacy Use {@link lib.element.NodeWS.prototype} instead. + */ + get nodews(){ + return this.NodeWS.prototype; } }, card:{ @@ -33306,7 +33777,7 @@ } } } - if(player) lib.element.player.emotion.apply(player,[pack,emotion]); + if(player) player.emotion(pack,emotion); }, chat:function(id,str){ if(lib.node.observing.contains(this)) return; @@ -33330,7 +33801,7 @@ } } } - if(player) lib.element.player.chat.call(player,str); + if(player) player.chat(str); }, giveup:function(player){ if(lib.node.observing.contains(this)||!player||!player._giveUp) return; @@ -33402,14 +33873,7 @@ ui.connecting.firstChild.innerHTML='重连成功'; } }, - onconnection:function(id){ - var ws={wsid:id}; - for(var i in lib.element.nodews){ - ws[i]=lib.element.nodews[i]; - } - lib.wsOL[id]=ws; - lib.init.connection(ws); - }, + onconnection:id=>lib.init.connection(lib.wsOL[id]=new lib.element.NodeWS(id)), onmessage:function(id,message){ if(lib.wsOL[id]){ lib.wsOL[id].onmessage(message); @@ -33622,7 +34086,7 @@ if(!map2[i[4]]){ var player=ui.roombase.add(''); player.roomindex=i; - player.initRoom=lib.element.player.initRoom; + player.initRoom=lib.element.Player.prototype.initRoom; player.addEventListener(lib.config.touchscreen?'touchend':'click',ui.click.connectroom); player.initRoom(i); ui.rooms.push(player); @@ -33741,9 +34205,7 @@ game.getRoomInfo=mode.game.getRoomInfo; } if(mode.element&&mode.element.player){ - for(var i in mode.element.player){ - lib.element.player[i]=mode.element.player[i]; - } + Object.defineProperties(lib.element.Player.prototype,Object.getOwnPropertyDescriptors(mode.element.player)); } if(mode.skill){ for(var i in mode.skill){ @@ -33849,9 +34311,7 @@ game.showIdentity=mode.game.showIdentity; } if(mode.element&&mode.element.player){ - for(var i in mode.element.player){ - lib.element.player[i]=mode.element.player[i]; - } + Object.defineProperties(lib.element.Player.prototype,Object.getOwnPropertyDescriptors(mode.element.player)); } if(mode.skill){ for(var i in mode.skill){ @@ -33953,8 +34413,8 @@ if(lib.config.die_move){ player.$dieflip(); } - if(lib.element.player.$dieAfter){ - lib.element.player.$dieAfter.call(player); + if(player.$dieAfter){ + player.$dieAfter(); } game.dead.push(player); } @@ -34368,96 +34828,135 @@ }], ['骰子',{ getSpan:()=>{ - return `🎲`; + const span=document.createElement('span'); + span.style.fontFamily='NonameSuits'; + span.textContent='🎲'; + return span.outerHTML; } }], ['SP',{ - getSpan:(prefix,name)=>{ - return `SP`; + getSpan:()=>{ + const span=document.createElement('span'),style=span.style; + style.writingMode=style.webkitWritingMode='horizontal-tb'; + style.fontFamily='MotoyaLMaru'; + style.transform='scaleY(0.85)'; + span.textContent='SP'; + return span.outerHTML; }, }], ['OL',{ - getSpan:(prefix,name)=>{ - return `OL`; + getSpan:()=>{ + const span=document.createElement('span'),style=span.style; + style.writingMode=style.webkitWritingMode='horizontal-tb'; + style.fontFamily='MotoyaLMaru'; + style.transform='scaleY(0.85)'; + span.textContent='OL'; + return span.outerHTML; }, }], ['RE',{ - getSpan:(prefix,name)=>{ - return `RE`; + getSpan:()=>{ + const span=document.createElement('span'),style=span.style; + style.writingMode=style.webkitWritingMode='horizontal-tb'; + style.fontFamily='MotoyaLMaru'; + style.transform='scaleY(0.85)'; + span.textContent='RE'; + return span.outerHTML; }, }], ['手杀',{ getSpan:(prefix,name)=>{ - const simple=(lib.config.buttoncharacter_prefix=='simple'); + const simple=lib.config.buttoncharacter_prefix=='simple',span=document.createElement('span'); if(lib.characterPack.shiji&&name in lib.characterPack.shiji){ - for(let i in lib.characterSort.shiji){ - if(lib.characterSort.shiji[i].includes(name)){ - prefix=get.translation(i).slice(-1); - break; - } + for(const entry of Object.entries(lib.characterSort.shiji)){ + if(!entry[1].includes(name)) continue; + prefix=get.translation(entry[0]).slice(-1); + break; } - if(simple) return `${prefix}`; - return `${prefix}`; + if(!simple){ + span.style.color='#def7ca'; + span.dataset.nature='watermm'; + } + span.innerHTML=prefix; } - if(simple) return '手杀'; - return `📱`; + else if(simple) span.textContent='手杀'; + else{ + span.style.fontFamily='NonameSuits'; + span.textContent='📱'; + } + return span.outerHTML; }, }], ['TW',{ - getSpan:(prefix,name)=>{ - return `TW`; + getSpan:()=>{ + const span=document.createElement('span'),style=span.style; + style.writingMode=style.webkitWritingMode='horizontal-tb'; + style.fontFamily='MotoyaLMaru'; + style.transform='scaleY(0.85)'; + span.textContent='TW'; + return span.outerHTML; }, }], ['TW神',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('TW')}${get.prefixSpan('神')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('TW')}${get.prefixSpan('神')}` }], ['TW将',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('TW')}${get.prefixSpan('将')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('TW')}${get.prefixSpan('将')}` }], ['OL神',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('OL')}${get.prefixSpan('神')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('OL')}${get.prefixSpan('神')}` }], ['旧神',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('旧')}${get.prefixSpan('神')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('旧')}${get.prefixSpan('神')}` }], ['旧晋',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('旧')}${get.prefixSpan('晋')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('旧')}${get.prefixSpan('晋')}` }], ['新杀SP',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('新杀')}${get.prefixSpan('SP')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('新杀')}${get.prefixSpan('SP')}` }], ['界SP',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('界')}${get.prefixSpan('SP')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('界')}${get.prefixSpan('SP')}` }], ['S特神',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('★')}${get.prefixSpan('神')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('★')}${get.prefixSpan('神')}` }], ['手杀界',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('手杀')}${get.prefixSpan('界')}` - }, + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('手杀')}${get.prefixSpan('界')}` }], ['战役篇神',{ - getSpan:(prefix,name)=>{ - return `${get.prefixSpan('战役篇')}${get.prefixSpan('神')}` - }, - }], + /** + * @returns {string} + */ + getSpan:()=>`${get.prefixSpan('战役篇')}${get.prefixSpan('神')}` + }] ]), groupnature:{ shen:'shen', @@ -35514,21 +36013,7 @@ game.ws.send(JSON.stringify(get.stringifiedResult(args))); } }, - sendTo:function(id,message){ - var ws={wsid:id}; - for(var i in lib.element.nodews){ - ws[i]=lib.element.nodews[i]; - } - var client={ - ws:ws, - id:ws.wsid, - closed:false - }; - for(var i in lib.element.client){ - client[i]=lib.element.client[i]; - } - client.send(message); - }, + sendTo:(id,message)=>new lib.element.Client(new lib.element.NodeWS(id)).send(message), createServer:function(){ lib.node.clients=[]; lib.node.banned=[]; @@ -38250,27 +38735,12 @@ next._trigger=event; next.setContent('createTrigger'); }, - createEvent:function(name,trigger,triggerevent){ - var next={ - name:name, - step:0, - finished:false, - next:[], - after:[], - custom:{ - add:{}, - replace:{} - }, - _aiexclude:[], - _notrigger:[], - _result:{}, - _set:[], - } - if(trigger!==false&&!game.online) next._triggered=0; - for(var i in lib.element.event){ - next[i]=lib.element.event[i]; - } - (triggerevent||_status.event).next.push(next); + /** + * @legacy Use {@link lib.element.Event.constructor} instead. + */ + createEvent:(name,trigger,triggerEvent)=>{ + const next=new lib.element.Event(name,trigger); + (triggerEvent||_status.event).next.push(next); return next; }, addCharacter:(name,information)=>{ @@ -42025,7 +42495,13 @@ return true; }); }, + /** + * @type {Player[]} + */ players:[], + /** + * @type {Player[]} + */ dead:[], imported:[], playerMap:{}, @@ -42383,7 +42859,7 @@ for(var i=0;i空房间
    '); player.roomindex=i; - player.initRoom=lib.element.player.initRoom; + player.initRoom=lib.element.Player.prototype.initRoom; player.addEventListener(lib.config.touchscreen?'touchend':'click',ui.click.connectroom); player.initRoom(list[i]); ui.rooms.push(player); @@ -50529,46 +51005,7 @@ return dialog; }, dialog:function(){ - var i; - var hidden=false; - var notouchscroll=false; - var forcebutton=false; - var noforcebutton=false; - var dialog=ui.create.div('.dialog'); - dialog.contentContainer=ui.create.div('.content-container',dialog); - dialog.content=ui.create.div('.content',dialog.contentContainer); - dialog.bar1=ui.create.div('.bar.top',dialog); - dialog.bar2=ui.create.div('.bar.bottom',dialog); - dialog.buttons=[]; - for(i in lib.element.dialog){ - dialog[i]=lib.element.dialog[i]; - } - for(i=0;i