diff --git a/character/rank.js b/character/rank.js index 0b8cf1ab1..81691dffe 100644 --- a/character/rank.js +++ b/character/rank.js @@ -961,6 +961,7 @@ window.noname_character_rank={ 're_wenpin', 'yue_zhoufei', 'ns_mengyou', + 'zhangyan', ], b:[ 'diy_feishi', diff --git a/character/sp.js b/character/sp.js index 72f66f354..89913697c 100755 --- a/character/sp.js +++ b/character/sp.js @@ -13,7 +13,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ sp_huben:['duanjiong','ol_mengda',"caohong","xiahouba","zhugeke","zumao","wenpin","litong","mazhong","heqi","quyi","luzhi","zangba","yuejin","dingfeng","wuyan","ol_zhuling","tianyu","huojun",'zhaoyǎn','dengzhong','ol_furong','macheng','ol_zhangyì','ol_zhujun','maxiumatie','luoxian','ol_huban','haopu','ol_qianzhao'], sp_liesi:['mizhu','weizi','ol_liuba','zhangshiping'], sp_default:["sp_diaochan","sp_zhaoyun","sp_sunshangxiang","sp_caoren","sp_jiangwei","sp_machao","sp_caiwenji","jsp_guanyu","jsp_huangyueying","sp_pangde","sp_jiaxu","yuanshu",'sp_zhangliao','sp_ol_zhanghe','sp_menghuo'], - sp_waitforsort:['ol_luyusheng','ol_pengyang','ol_tw_zhangji','ol_feiyi','ol_lvboshe'], + sp_waitforsort:['ol_luyusheng','ol_pengyang','ol_tw_zhangji','ol_feiyi','ol_lvboshe','zhangyan'], sp_qifu:["caoying",'panshu',"caochun","yuantanyuanshang",'caoshuang','wolongfengchu','guansuo','baosanniang','fengfangnv','jin_zhouchu'], sp_wanglang:['ol_wanglang','ol_puyuan','ol_zhouqun'], sp_zhongdan:["cuiyan","huangfusong"], @@ -33,6 +33,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, }, character:{ + zhangyan:['male','qun',4,['olsuji','ollangdao']], ol_tw_zhangji:['male','wei',3,['skill_zhangji_A','skill_zhangji_B'],['unseen']], ol_feiyi:['male','shu',3,['skill_feiyi_A','skill_feiyi_B'],['unseen']], ol_lvboshe:['male','qun',4,['skill_lvboshe'],['unseen']], @@ -203,6 +204,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ luzhi:['male','wei',3,['qingzhong','weijing']] }, characterIntro:{ + zhangyan:'张燕,本姓褚,生卒年不详,常山真定(今河北正定南)人,东汉末年黑山军首领。张燕剽捍,敏捷过人,军中称为“飞燕”。官渡之战时投降曹操,被任命为平北将军,封安国亭侯。死后其子张方袭爵。', lushi:'卢氏,五斗米教主张衡妻,张鲁母,擅长驻颜之术,常年令自己保持少女的容颜。常拜访刘焉,与其交好。', lvboshe:'吕伯奢,东汉成皋(今河南荥阳)人,曹操父亲曹嵩的故友。曹操与陈宫在逃离董卓避祸,返回乡里的途中借宿于吕伯奢家,未伤其人,有贼八人欲捉曹操,曹操杀之,明罗贯中在历史小说《三国演义》中将这段历史进行了丑化加工,也成为小说中曹操名言“宁教我负天下人,休教天下人负我”的出处。', caoxi:'曹羲(?-249年),字昭叔。曹真之子,曹爽之弟。为人有学识,明律法。司马懿曾组织朝议改革九品中正制废除九品而留中正,曹羲认为此举并无区别,最终都是决定于人的人治。曹爽掌权后,受封中领军,掌握禁兵,封安乡侯。曹爽及诸兄弟轻视司马懿,恣意妄为,经常外出狩猎,曹羲屡次劝谏,不被采纳。249年,司马懿发动高平陵政变,被夷三族。', @@ -704,6 +706,285 @@ game.import('character',function(lib,game,ui,get,ai,_status){ }, }, skill:{ + //张燕 + olsuji:{ + audio:2, + trigger:{global:'phaseUseBegin'}, + filter:function(event,player){ + if(!event.player.isDamaged()) return false; + return _status.connectMode&&player.countCards('hes')||!_status.connectMode&&player.hasCard(card=>{ + return get.color(card)=='black'; + },'hes'); + }, + direct:true, + content:[ + (event,map)=>{ + var player=map.player,trigger=map.trigger; + var next=player.chooseToUse(); + next.set('openskilldialog',`###${get.prompt('olsuji')}###将一张黑色牌当【杀】使用${ + player==trigger.player?'':`。若${get.translation(trigger.player)}受到了此【杀】的伤害,你获得其一张牌。` + }`); + next.set('norestore',true); + next.set('_backupevent','olsuji_backup'); + next.set('addCount',false); + next.set('logSkill','olsuji'); + next.set('custom',{ + add:{}, + replace:{window:function(){}} + }); + next.backup('olsuji_backup'); + }, + (event,map)=>{ + if(map.result.bool){ + var player=map.player,trigger=map.trigger; + if(trigger.player.isIn()&&trigger.player.hasHistory('damage',evt=>{ + return evt.card&&evt.card.storage&&evt.card.storage.olsuji; + })&&trigger.player.countGainableCards(player,'he')) player.gainPlayerCard(trigger.player,'he',true); + } + }, + ], + subSkill:{ + backup:{ + filterCard:function(card){ + return get.itemtype(card)=='card'&&get.color(card)=='black'; + }, + viewAs:{ + name:'sha', + storage:{olsuji:true}, + }, + selectCard:1, + position:'hes', + ai1:function(card){ + return 5-get.value(card); + }, + precontent:function(){ + delete event.result.skill; + }, + }, + }, + }, + ollangdao:{ + audio:2, + trigger:{player:'useCardToPlayer'}, + filter:function(event,player){ + if(event.card.name!='sha') return false; + return event.isFirstTarget&&event.targets.length==1&&player.getStorage('ollangdao').length<3; + }, + logTarget:'target', + onremove:true, + check:function(event,player){ + if(get.attitude(player,event.target)>0){ + if(player.getStorage('ollangdao').includes(1)&&game.hasPlayer(current=>{ + return player.canUse(event.card,current)&&get.effect(current,event.card,player,player)>0; + })) return event.getRand()<0.5; + return false; + } + return event.target.getHp()<=2||player.getDamagedHp()>1||!player.hasCard({color:'black'},'hes'); + }, + content:function*(event,map){ + var player=map.player,trigger=map.trigger,result=map.result; + var target=trigger.target; + var send=function(card,list){ + var next=game.createEvent('ollangdao_choose',false); + next.setContent(lib.skill.ollangdao.contentx); + next.set('card',card); + next.set('list',list); + game.resume(); + }; + var sendback=function(result,player){ + if(!result) result={}; + if(typeof result.index!=='number'||result.index<0){ + result.index=[0,1,2].find(i=>!event.player.getStorage('ollangdao').includes(i)); + } + results.push([player,result]); + }; + var ai_targets=[]; + var results=[]; + var players=[player,target]; + var withme=false,withol=false,withai=false; + for(var i=0;i{ + return !trigger.targets.includes(current)&&player.canUse(trigger.card,current)&&get.effect(current,trigger.card,player,target)<0; + })) list.removeArray([0,2]); + if(player.getStorage('ollangdao').includes(2)) list.remove(0); + } + else{ + if(!game.hasPlayer(current=>{ + return !trigger.targets.includes(current)&&player.canUse(trigger.card,current)&&get.effect(current,trigger.card,player,target)>0; + })) list.remove(1); + if(!list.includes(1)) list.remove(0); + } + if(list.length) index=list.randomGet(); + sendback({index:index},target); + ai_targets.splice(i--,1); + } + } + if(ai_targets.length){ + ai_targets.randomSort(); + setTimeout(function(){ + event.interval=setInterval(function(){ + var target=ai_targets.shift(); + var list=[0,1,2].removeArray(player.getStorage('ollangdao')); + var index=list[0]; + if(get.attitude(target,player)<0){ + if(!game.hasPlayer(current=>{ + return !trigger.targets.includes(current)&&player.canUse(trigger.card,current)&&get.effect(current,trigger.card,player,target)<0; + })) list.removeArray([0,2]); + if(player.getStorage('ollangdao').includes(2)) list.remove(0); + } + else{ + if(!game.hasPlayer(current=>{ + return !trigger.targets.includes(current)&&player.canUse(trigger.card,current)&&get.effect(current,trigger.card,player,target)>0; + })) list.remove(1); + if(!list.includes(1)) list.remove(0); + } + if(list.length) index=list.randomGet(); + sendback({index:index},target); + if(!ai_targets.length){ + clearInterval(event.interval); + if(withai) game.resume(); + } + },_status.connectMode?750:75); + },500); + } + } + if(withme){ + result=yield next; + if(_status.connectMode){ + game.me.unwait(result,game.me); + } + else{ + if(!result) result={}; + if(typeof result.index!=='number'||result.index<0){ + result.index=[0,1,2].find(i=>!event.player.getStorage('ollangdao').includes(i)); + } + results.push([player,result]); + } + } + if(withol&&!event.resultOL){ + game.pause(); + yield null; + } + if(ai_targets.length>0){ + withai=true; + game.pause(); + yield null; + } + if(_status.connectMode){ + for(var i of [player,target]) i.hideTimer(); + } + var chosenCount=[0,0,0]; + results.sort((a,b)=>lib.sort.seat(a[0],b[0])); + player.when('useCardAfter') + .assign({ + card:trigger.card + }) + .then(()=>{ + var card=get.info(event.name).card; + var dieEvts=game.getGlobalHistory('everything',evt=>evt.name=='die'); + if(trigger.card==card&&!game.hasPlayer2(current=>{ + for(var evt of dieEvts){ + if(evt.player!=current) continue; + var evtx=evt.getParent(2); + if(evtx.name!='damage') continue; + if(evtx.card&&evtx.card==card) return true; + } + return false; + },true)){ + var toRemove=card.storage.ollangdao_remove; + var list=[0,1,2].filter(i=>(toRemove>>i)&1); + if(!list.length) return; + player.markAuto('ollangdao',list); + game.log(player,'移去了','#g【狼蹈】','的','#y选项'+list.map(i=>{ + return get.cnNumber(i+1,true); + }).join('、')); + } + }); + if(!trigger.card.storage) trigger.card.storage={}; + if(!trigger.card.storage.ollangdao_remove) trigger.card.storage.ollangdao_remove=0; + var config=[['伤害+1','fire'],['目标+1','wood'],['不能响应','water']]; + for(var res of results){ + var target=res[0],result=res[1]; + if(!target||!result) continue; + var ind=result.index; + var conf=config[ind]; + trigger.card.storage.ollangdao_remove|=1<{ + return !_status.event.targets.includes(target)&&player.canUse(_status.event.card,target); + }).set('targets',trigger.targets).set('ai',target=>{ + var player=_status.event.player; + return get.effect(target,_status.event.card,player,player); + }).set('card',trigger.card); + if(result.bool){ + if(!event.isMine()&&!event.isOnline()) game.delayex(); + var targets=result.targets; + player.line(targets); + trigger.targets.addArray(targets); + game.log(targets,'也成为了',trigger.card,'的目标'); + } + }, + contentx:function(){ + 'step 0' + var name=get.translation(card); + var choices=[],choiceList=[ + `令${name}伤害基数+1`, + `令${name}可以多选择一个目标`, + `令${name}不可被响应` + ]; + [0,1,2].forEach((item,index)=>{ + if(event.list.includes(item)){ + choiceList[index]=`${choiceList[index]}` + } + else choices.push(`选项${get.cnNumber(index+1,true)}`); + }); + game.me.chooseControl(choices).set('prompt','狼蹈:请选择一项').set('choiceList',choiceList).set('ai',()=>{ + return _status.event.controls.randomGet(); + }); + 'step 1' + event.result={index:['选项一','选项二','选项三'].indexOf(result.control)}; + }, + intro:{ + content:(storage,player)=>`已移除选项${storage.map(i=>get.cnNumber(i+1,true)).join('、')}`, + }, + }, //张既 skill_zhangji_A:{ audio:2, @@ -1225,7 +1506,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ content:function(){ 'step 0' var info=lib.skill.olgangshu.getInfo(player); - player.chooseControl('攻击范围('+info[0]+')','摸牌数('+info[1]+')','使用【杀】的上限('+info[2]+')','cancel2').set('prompt',get.prompt('olgangshu')).set('prompt2','
令以下一个数值+1(每项至多+5):
1.攻击范围;
2.下个摸牌阶段的摸牌数;
3.使用【杀】的次数上限。
').set('ai',()=>{ + player.chooseControl('攻击范围('+info[0]+')','摸牌数('+info[1]+')','使用杀的上限('+info[2]+')','cancel2').set('prompt',get.prompt('olgangshu')).set('prompt2','
令以下一个数值+1(每项至多+5):
1.攻击范围;
2.下个摸牌阶段的摸牌数;
3.使用【杀】的次数上限。
').set('ai',()=>{ return _status.event.choice; }).set('choice',function(){ var info=lib.skill.olgangshu.getInfo(player); @@ -24456,6 +24737,23 @@ game.import('character',function(lib,game,ui,get,ai,_status){ if(player.storage.skill_lvboshe) return '农民的回合结束时:阴,你可以令地主进行一个额外回合;阳,你可以令其进行一个额外回合。'; return '农民的回合结束时:阴,你可以令地主进行一个额外回合;阳,你可以令其进行一个额外回合。'; }, + ollangdao:function(player){ + var str='当你使用【杀】指定唯一目标时,你可以与该目标角色同时选择一项:'; + var list=[ + '1.令此【杀】伤害基数+1;', + '2.令你可以为此【杀】多选择一个目标;', + '3.令此【杀】不可被响应。' + ]; + var storage=player.getStorage('ollangdao'); + list.forEach((item,index)=>{ + if(storage.includes(index)){ + str+=`${item}`; + } + else str+=item; + }) + str+='然后若没有角色因此【杀】死亡,你移除本次被选择的项。'; + return str; + }, }, characterReplace:{ shixie:['shixie','dc_shixie'], @@ -25708,6 +26006,11 @@ game.import('character',function(lib,game,ui,get,ai,_status){ ol_lvboshe:'吕伯奢', skill_lvboshe:'技能', skill_lvboshe_info:'农民的回合结束时:阴,你可以令地主进行一个额外回合;阳,你可以令其进行一个额外回合。', + zhangyan:'张燕', + olsuji:'肃疾', + olsuji_info:'一名角色的出牌阶段开始时,若其已受伤,你可以将一张黑色牌当【杀】使用。若其受到此【杀】的伤害,你获得其一张牌。', + ollangdao:'狼蹈', + ollangdao_info:'当你使用【杀】指定唯一目标时,你可以与该目标角色同时选择一项:1.令此【杀】伤害基数+1;2.令你可以为此【杀】多选择一个目标;3.令此【杀】不可被响应。然后若没有角色因此【杀】死亡,你移除本次被选择的项。', sp_tianji:'天极·皇室宗亲', diff --git a/character/xianding.js b/character/xianding.js index 6850f0c48..4cc01cc12 100644 --- a/character/xianding.js +++ b/character/xianding.js @@ -94,8 +94,8 @@ game.import('character',function(lib,game,ui,get,ai,_status){ sp2_wangzhe:['dc_daxiaoqiao','dc_sp_machao'], sp2_doukou:['re_xinxianying','huaman','xuelingyun','dc_ruiji','duanqiaoxiao','tianshangyi'], sp2_jichu:['zhaoang','dc_liuye','dc_wangyun','yanghong','huanfan','xizheng'], - sp2_yuxiu:['dongguiren','dc_tengfanglan','zhangjinyun','zhoubuyi'], - sp2_qifu:['ol_guansuo','dc_zhaoxiang','dc_xujing'], + sp2_yuxiu:['dongguiren','dc_tengfanglan','zhangjinyun','zhoubuyi','dc_xujing'], + sp2_qifu:['ol_guansuo','dc_zhaoxiang'], sp2_gaoshan:['wanglang','liuhui'], sp2_wumiao:['wu_zhugeliang','wu_luxun'], } diff --git a/game/game.js b/game/game.js index e8f4dc478..29edb2a08 100644 --- a/game/game.js +++ b/game/game.js @@ -282,6 +282,17 @@ if(lineColor.length) lib.lineColor.set(nature,lineColor); lib.nature.set(nature,order); if(background.length>0) lib.natureBg.set(nature,background); + if(config.audio){ + for(let key in config.audio){ + if(!lib.natureAudio[key]){ + lib.natureAudio[key] = config.audio[key]; + }else{ + for(let key2 in config.audio[key]){ + lib.natureAudio[key][key2] = config.audio[key][key2]; + } + } + } + } let color1,color2; if (typeof config.color=="string"&&/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(config.color)){ @@ -18002,6 +18013,8 @@ cardaudio=false; } if(cardaudio) game.broadcastAll((player,card)=>{ + game.playCardAudio(card,player); + /* if(!lib.config.background_audio||get.type(card)=='equip'&&!lib.config.equip_audio) return; const sex=player.sex=='female'?'female':'male'; var nature=get.natureList(card)[0]; @@ -18016,7 +18029,7 @@ else if(audio.startsWith('ext:')) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${card.name}_${sex}.${audioInfo[2]||'mp3'}`); else game.playAudio('card',sex,`${audioInfo[0]}.${audioInfo[1]||'mp3'}`); } - else game.playAudio('card',sex,card.name); + else game.playAudio('card',sex,card.name);*/ },player,card); if(event.animate!=false&&event.line!=false){ if(card.name=='wuxie'&&event.getParent()._info_map){ @@ -18826,6 +18839,8 @@ } else if(!event.nopopup) player.tryCardAnimate(card,card.name,'wood'); if(cardaudio&&event.getParent(3).name=='useCard') game.broadcastAll((player,card)=>{ + game.playCardAudio(card,player); + /* if(!lib.config.background_audio) return; const sex=player.sex=='female'?'female':'male',audio=lib.card[card.name].audio; if(typeof audio=='string'){ @@ -18834,7 +18849,7 @@ else if(audio.startsWith('ext:')) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${card.name}_${sex}.${audioInfo[2]||'mp3'}`); else game.playAudio('card',sex,`${audioInfo[0]}.${audioInfo[1]||'mp3'}`); } - else game.playAudio('card',sex,card.name); + else game.playAudio('card',sex,card.name);*/ },player,card); if(event.skill){ if(player.stat[player.stat.length-1].skill[event.skill]==undefined){ @@ -19572,29 +19587,30 @@ event.trigger('damageBegin4'); "step 4" //moved changeHujia to changeHp - if(['fire','thunder','ice'].contains(event.nature)){ - if(player.hujia>0&&!player.hasSkillTag('nohujia')&&event.nature!='ice'){ - game.broadcastAll(function(num){ - if(lib.config.background_audio) game.playAudio('effect','hujia_damage_'+event.nature+(num>1?'2':'')); - },num); + if(player.hujia>0 && !player.hasSkillTag('nohujia')){ + var damageAudioInfo = lib.natureAudio.hujia_damage[event.nature]; + if(!damageAudioInfo || damageAudioInfo == 'normal'){ + damageAudioInfo = 'effect/hujia_damage'+(num>1?'2':'')+'.mp3'; + }else if(damageAudioInfo == 'default'){ + damageAudioInfo = 'effect/hujia_damage_'+event.nature+(num>1?'2':'')+'.mp3'; + }else{ + damageAudioInfo = damageAudioInfo[num >1 ?2:1]; } - else{ - game.broadcastAll(function(num){ - if(lib.config.background_audio) game.playAudio('effect','damage_'+event.nature+(num>1?'2':'')); - },num); - } - } - else{ - if(player.hujia>0&&!player.hasSkillTag('nohujia')){ - game.broadcastAll(function(num){ - if(lib.config.background_audio) game.playAudio('effect','hujia_damage'+(num>1?'2':'')); - },num); - } - else{ - game.broadcastAll(function(num){ - if(lib.config.background_audio) game.playAudio('effect','damage'+(num>1?'2':'')); - },num); + game.broadcastAll(function(damageAudioInfo){ + if(lib.config.background_audio) game.playAudio(damageAudioInfo); + },damageAudioInfo); + }else{ + var damageAudioInfo = lib.natureAudio.damage[event.nature]; + if(!damageAudioInfo || damageAudioInfo == 'normal'){ + damageAudioInfo = 'effect/damage'+(num>1?'2':'')+'.mp3'; + }else if(damageAudioInfo == 'default'){ + damageAudioInfo = 'effect/damage_'+event.nature+(num>1?'2':'')+'.mp3'; + }else{ + damageAudioInfo = damageAudioInfo[num >1 ?2:1]; } + game.broadcastAll(function(damageAudioInfo){ + if(lib.config.background_audio) game.playAudio(damageAudioInfo); + },damageAudioInfo); } var str=event.unreal?'视为受到了':'受到了'; if(source) str+='来自'+(source==player?'自己':get.translation(source))+'的'; @@ -33966,6 +33982,45 @@ ['stab',10], ['poison',50] ]), + natureAudio:{ + damage:{ + 'fire':'default',//默认,即语音放置在audio/effect下,以damage_fire.mp3 damage_fire2.mp3命名。 + 'thunder':'default', + 'ice':'default', + 'stab':'normal',//正常,即与普通伤害音效相同。 + /* + 'example':{ + 1:'../extension/XXX/damage_example.mp3',//1点伤害。 + 2:'../extension/XXX/damage_example2.mp3',//2点及以上伤害 + } + */ + }, + hujia_damage:{ + 'fire':'default',//默认,即语音放置在audio/effect下,以hujia_damage_fire.mp3 hujia_damage_fire2.mp3命名。 + 'thunder':'default', + 'ice':'normal',//正常,即与普通伤害音效相同。 + /* + 'example':{ + 1:'../extension/XXX/damage_example.mp3',//1点伤害。 + 2:'../extension/XXX/damage_example2.mp3',//2点及以上伤害 + } + */ + }, + sha:{ + 'fire':'default',//默认,即语音放置在audio/card/male与audio/card/female下,命名为sha_fire.mp3 + 'thunder':'default', + 'ice':'default', + 'stab':'default', + 'poison':'normal',//正常,即播放“杀”的音效。 + 'kami':'normal', + /* + 'example':{ + 'male':'../extension/XXXX/sha_example_male.mp3', + 'female':'../extension/XXXX/sha_example_female.mp3' + } + */ + } + }, linked:['fire','thunder','kami','ice'], natureBg:new Map([ ['stab','image/card/cisha.png'] @@ -35283,102 +35338,86 @@ }); return audio; }, - trySkillAudio:function(skill,player,directaudio){ - game.broadcast(game.trySkillAudio,skill,player,directaudio); + trySkillAudio:function(skill,player,directaudio,nobroadcast/*,index*/){ + if(!nobroadcast) game.broadcast(game.trySkillAudio,skill,player,directaudio,nobroadcast/*,index*/); var info=get.info(skill); if(!info) return; if(!lib.config.background_speak) return; + if(info.direct&&!directaudio) return; + if(lib.skill.global.includes(skill)&&!lib.skill[skill].forceaudio) return; if(typeof player=='string') player={name:player}; - else{ - if(info.direct&&!directaudio) return; - if(lib.skill.global.includes(skill)&&!lib.skill[skill].forceaudio) return; + + function getAudioList(skill,player,history,fixedNum){ + let info=lib.skill[skill]; + if(!info) return []; + if(!history) history=[]; + if(history.includes(skill)){//直接跳出 + console.trace(`${skill} in ${history} forms a deadlock`); + if(info.audio!==false) return [[skill]];//标记为playSkillAudio + return []; + } + history.push(skill); + + let audioInfo=info.audio; + if(info.audioname2&&player){ + if(info.audioname2[player.name]) audioInfo=info.audioname2[player.name]; + else if(info.audioname2[player.name1]) audioInfo=info.audioname2[player.name1]; + else if(info.audioname2[player.name2]) audioInfo=info.audioname2[player.name2]; + } + if(typeof audioInfo=='function') audioInfo=audioInfo(player); + + let audioname=''; + if(Array.isArray(info.audioname)&&player){ + if(info.audioname.includes(player.name)) audioname=`_${player.name}`; + else if(info.audioname.includes(player.name1)) audioname=`_${player.name1}`; + else if(info.audioname.includes(player.name2)) audioname=`_${player.name2}`; + } + + let audioList=parseAudio(skill,audioInfo,audioname,player,history,fixedNum); + if(fixedNum&&fixedNumtotal.addArray(parseAudio(skill,i,audioname,player,history,fixedNum)),[]); } - break; - } - if(Array.isArray(info.audioname)&&player){ - if(info.audioname.includes(player.name)&&(!info.audioname2||!info.audioname2[player.name])) audioName+='_'+player.name; - else if(info.audioname.includes(player.name1)&&(!info.audioname2||!info.audioname2[player.name1])) audioName+='_'+player.name1; - else if(info.audioname.includes(player.name2)&&(!info.audioname2||!info.audioname2[player.name2])) audioName+='_'+player.name2; - } - if(typeof audioInfo=='string'){ - if(audioInfo.startsWith('db:')){ - audioInfo=audioInfo.split(':'); - if(audioInfo.length<4) return; - if(audioInfo[3]=='true') game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,audioInfo[2],`${audioName}.${audioInfo[4]||'mp3'}`); + + if(!['string','number','boolean'].includes(typeof audioInfo)) return []; + if(audioInfo===false) return []; + if(typeof audioInfo=='string'&&lib.skill[audioInfo]) return getAudioList(audioInfo,player,history,fixedNum); + audioInfo=String(audioInfo); + + let audioList=[]; + let list=audioInfo.match(/(?:(.*):|^)(true|\d*)(?::(.*)|$)/); + if(list&&list[2]){ + list=list.slice(1);//形如[路径,number/true,格式]的形式 + if(list[1]=='true') audioList.add(`${list[0]||'skill'}/${skill}${audioname}.${list[2]||'mp3'}`); else{ - audioInfo[3]=fixedNum?Math.min(parseInt(audioInfo[3]),fixedNum):parseInt(audioInfo[3]); - if(!audioInfo[3]) return; - game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,audioInfo[2],`${audioName}${Math.floor(audioInfo[3]*Math.random())+1}.${audioInfo[4]||'mp3'}`); - } - } - else if(audioInfo.startsWith('ext:')){ - audioInfo=audioInfo.split(':'); - if(audioInfo.length<3) return; - if(audioInfo[2]=='true') game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${audioName}.${audioInfo[3]||'mp3'}`); - else{ - audioInfo[2]=fixedNum?Math.min(parseInt(audioInfo[2]),fixedNum):parseInt(audioInfo[2]); - if(!audioInfo[2]) return; - game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${audioName}${Math.floor(audioInfo[2]*Math.random())+1}.${audioInfo[3]||'mp3'}`); + list[1]=parseInt(list[1]); + for(let i=1;i<=list[1];i++){ + audioList.add(`${list[0]||'skill'}/${skill}${audioname}${i}.${list[2]||'mp3'}`); + } } } + else audioList.add(`${/(?:^db:|^ext:|\/)/.test(audioInfo)?'':'skill/'}${audioInfo}`); + return audioList; } - else if(typeof audioInfo=='number'){ - if(fixedNum) audioInfo=Math.min(audioInfo, fixedNum); - game.playAudio('skill',`${audioName}${Math.floor(audioInfo*Math.random())+1}`); - } - //直接指定配音文件名的新格式 - else if(typeof audioInfo=="object"){ - if(!("type" in audioInfo&&audioInfo.type=="direct"&&"files" in audioInfo)) return; - let audioFiles=audioInfo.files; - if(typeof audioFiles!="object") return; - if(!Array.isArray(audioFiles)){ - if(!player) return; - if(player.name&&player.name in audioFiles&&(!info.audioname2||!info.audioname2[player.name]))audioFiles=audioFiles[player.name]; - else if(player.name1&&player.name1 in audioFiles&&(!info.audioname2||!info.audioname2[player.name1]))audioFiles=audioFiles[player.name1]; - else if(player.name2&&player.name2 in audioFiles&&(!info.audioname2||!info.audioname2[player.name2]))audioFiles=audioFiles[player.name2]; - } - if(!Array.isArray(audioFiles)) return; - let length=audioFiles.length; - if(fixedNum)length=Math.min(length,fixedNum); - //game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${audioName}${+1}.${audioInfo[3]||'mp3'}`); - game.playAudio(audioFiles[Math.floor(length*Math.random())]); - } - else if(audioInfo) game.playAudio('skill',audioName); - else if(info.audio!==false) game.playSkillAudio(audioName); + + let list=getAudioList(skill,player); + // console.log(skill,lib.skill[skill]&&lib.skill[skill].audio,list); + if(!list.length) return; + // if(index) index=index%list.length||list.length; + // let audio=list[index?index-1:Math.floor(Math.random()*list.length)]; + let audio=list[Math.floor(Math.random()*list.length)]; + if(Array.isArray(audio)) return game.playSkillAudio(audio[0]); + return game.playAudio(audio); }, playSkillAudio:function(name,index){ if(_status.video&&arguments[1]!='video') return; @@ -35431,6 +35470,36 @@ }; ui.window.appendChild(audio); }, + playCardAudio:function(card,sex){ + if(typeof card === 'string'){ + card = {name:card}; + } + if(get.itemtype(sex) === 'player'){ + sex = (sex.sex == 'female'?'female':'male'); + }else if(typeof sex == 'string'){ + sex = (sex == 'female'?'female':'male'); + } + if(!lib.config.background_audio||get.type(card)=='equip'&&!lib.config.equip_audio) return; + var nature=get.natureList(card)[0]; + if(lib.natureAudio[card.name]){ + let useAudio = lib.natureAudio[card.name][nature]; + if(useAudio === 'default'){ + game.playAudio('card',sex,`${card.name}_${nature}`); + return; + }else if(useAudio && useAudio[sex]){ + game.playAudio(useAudio[sex]); + return; + } + } + const audio=lib.card[card.name].audio; + if(typeof audio=='string'){ + const audioInfo=audio.split(':'); + if(audio.startsWith('db:')) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,audioInfo[2],`${card.name}_${sex}.${audioInfo[3]||'mp3'}`); + else if(audio.startsWith('ext:')) game.playAudio(`${audioInfo[0]}:${audioInfo[1]}`,`${card.name}_${sex}.${audioInfo[2]||'mp3'}`); + else game.playAudio('card',sex,`${audioInfo[0]}.${audioInfo[1]||'mp3'}`); + } + else game.playAudio('card',sex,card.name); + }, playBackgroundMusic:()=>{ if(lib.config.background_music=='music_off'){ ui.backgroundMusic.src=''; @@ -40832,7 +40901,17 @@ checkMod:function(){ const argumentArray=Array.from(arguments),name=argumentArray[argumentArray.length-2]; let skills=argumentArray[argumentArray.length-1]; - if(skills.getSkills) skills=skills.getModableSkills(_status.event.useCache === true); + if(typeof skills.getModableSkills == 'function'){ + skills=skills.getModableSkills(_status.event.useCache === true); + }else if(typeof skills.getSkills == 'function'){ + skills=skills.getSkills().concat(lib.skill.global); + game.expandSkills(skills); + skills = skills.filter(function(skill){ + var info = get.info(skill); + return info && info.mod; + }); + skills.sort((a,b)=>get.priority(a)-get.priority(b)); + } const arg=argumentArray.slice(0,-2); skills.forEach(value=>{ var mod = get.info(value).mod[name]; @@ -59280,7 +59359,7 @@ if(node._nointro) return; if(typeof node._customintro=='function'){ if(node._customintro(uiintro,evt)===false) return; - lib.placePoppedDialog(uiintro,evt); + if(evt)lib.placePoppedDialog(uiintro,evt); } else if(Array.isArray(node._customintro)){ var caption=node._customintro[0]; diff --git a/image/character/zhangyan.jpg b/image/character/zhangyan.jpg new file mode 100644 index 000000000..41b9486fc Binary files /dev/null and b/image/character/zhangyan.jpg differ