From 096e7bd96407be96096c2a6840b5667dc50fcf59 Mon Sep 17 00:00:00 2001 From: shijian <2954700422@qq.com> Date: Wed, 6 Dec 2023 19:40:10 +0800 Subject: [PATCH 1/6] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=BC=82=E6=AD=A5content?= =?UTF-8?q?=E4=BB=A5=E5=8F=8AGameEvent#toPromise=EF=BC=8C=E9=83=AD?= =?UTF-8?q?=E5=98=89=E5=92=8C=E4=BA=8C=E5=BC=A0=E4=BD=9C=E4=B8=BA=E6=B5=8B?= =?UTF-8?q?=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- character/shenhua.js | 7 +- character/standard.js | 75 ++++++- game/game.js | 478 ++++++++++++++++++++++++++---------------- 3 files changed, 376 insertions(+), 184 deletions(-) diff --git a/character/shenhua.js b/character/shenhua.js index 4113463b9..90c8698e4 100755 --- a/character/shenhua.js +++ b/character/shenhua.js @@ -3952,10 +3952,15 @@ game.import('character',function(lib,game,ui,get,ai,_status){ if(target.isMin()) return false; return player!=target&&target.canEquip(card); }, - content:function(){ + content2:function(){ target.equip(cards[0]); player.draw(); }, + async content(event, trigger, player){ + await event.target.promises.equip(event.cards[0]); + game.log('老子装完了,还没摸牌') + await player.promises.draw(); + }, discard:false, lose:false, prepare:function(cards,player,targets){ diff --git a/character/standard.js b/character/standard.js index afbce7932..ec99b9c47 100755 --- a/character/standard.js +++ b/character/standard.js @@ -588,7 +588,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ filter:function(event){ return (event.num>0) }, - content:function(){ + content2:function(){ 'step 0' event.count=trigger.num; 'step 1' @@ -659,6 +659,79 @@ game.import('character',function(lib,game,ui,get,ai,_status){ event.goto(1); } }, + async content(event, trigger, player) { + console.log('step 0'); + event.count = trigger.num; + while (event.count > 0) { + console.log('step 1'); + event.count--; + const { cards } = await game.cardsGotoOrdering(get.cards(2)).toPromise(); + if (_status.connectMode) game.broadcastAll(function () { _status.noclearcountdown = true }); + event.given_map = {}; + + if (!cards.length) return event.finish(); + do { + console.log('step 2'); + const { result: { bool, links } } = + cards.length == 1 ? + { result: { links: cards.slice(0), bool: true } } : + await player.promises.chooseCardButton('遗计:请选择要分配的牌', true, cards, [1, cards.length]) + .set('ai', function (button) { + if (ui.selected.buttons.length == 0) return 1; + return 0; + }); + if (!bool) return event.finish(); + console.log('step 3'); + cards.removeArray(links); + event.togive = links.slice(0); + const { result: { targets } } = await player.promises.chooseTarget('选择一名角色获得' + get.translation(links), true) + .set('ai', function (target) { + var att = get.attitude(_status.event.player, target); + if (_status.event.enemy) { + return -att; + } + else if (att > 0) { + return att / (1 + target.countCards('h')); + } + else { + return att / 100; + } + }) + .set('enemy', get.value(event.togive[0], player, 'raw') < 0); + console.log('step 4'); + if (targets.length) { + const id = targets[0].playerid, + map = event.given_map; + if (!map[id]) map[id] = []; + map[id].addArray(event.togive); + } + } while (cards.length > 0); + console.log('step 5'); + if (_status.connectMode) { + game.broadcastAll(function () { delete _status.noclearcountdown; game.stopCountChoose() }); + } + const list = []; + for (const i in event.given_map) { + const source = (_status.connectMode ? lib.playerOL : game.playerMap)[i]; + player.line(source, 'green'); + list.push([source, event.given_map[i]]); + } + await game.loseAsync({ + gain_list: list, + giver: player, + animate: 'draw', + }).setContent('gaincardMultiple').toPromise(); + console.log('step 6'); + if (event.count > 0 && player.hasSkill(event.name) && !get.is.blocked(event.name, player)) { + const { result: { bool: repeat } } = await player.promises.chooseBool(get.prompt2(event.name)).set('frequentSkill', event.name); + console.log('step 7'); + if (repeat) { + player.logSkill(event.name); + } + } + else return event.finish(); + } + }, ai:{ maixie:true, maixie_hp:true, diff --git a/game/game.js b/game/game.js index e7840298e..45e204a9b 100644 --- a/game/game.js +++ b/game/game.js @@ -47,6 +47,7 @@ new Promise(resolve=>{ } } const GeneratorFunction=(function*(){}).constructor; + const AsyncFunction=(async function(){}).constructor; // gnc: GeNCoroutine const gnc={ of:fn=>gnc.is.generatorFunc(fn)?function genCoroutine(){ @@ -21030,6 +21031,22 @@ new Promise(resolve=>{ }; player.queueCount=0; player.outCount=0; + /** + * 这部分应该用d.ts写。目前只给出大概类型 + * @type { {[key in keyof Player]: (...args) => Promise & GameEvent} } + */ + player.promises=new Proxy({},{ + get(target,prop){ + const eventKeys=Object.keys(lib.element.player).filter(key=>typeof lib.element.player[key]=='function'); + if (eventKeys.includes(prop)){ + return function (...args) { + /** @type { GameEvent } */ + const event=player[prop](...args); + return event.toPromise(); + }; + } + } + }); } buildEventListener(noclick){ let player = this; @@ -31288,6 +31305,14 @@ new Promise(resolve=>{ this._notrigger=[]; this._result={}; this._set=[]; + /** + * @type {boolean} 这个事件是否使用异步函数处理 + **/ + this.async=false; + /** + * @type {null|(event: GameEvent)=>any} 这个异步事件对应Promise的resolve函数 + **/ + this.resolve=null; if(trigger!==false&&!game.online) this._triggered=0; } static initialGameEvent(){ @@ -31517,7 +31542,10 @@ new Promise(resolve=>{ switch(typeof item){ case "object": case "function": - this.content=lib.init.parsex(item); + if(item instanceof AsyncFunction){ + this.content=item; + } + else this.content=lib.init.parsex(item); break; default: try{ @@ -32073,6 +32101,87 @@ new Promise(resolve=>{ this.unreal; throw new Error('Do not call this method'); } + /** + * 事件转为Promise化 + * + * 注: 该函数在async content中执行时,必须在所有setxx函数执行后执行。 + * @returns { Promise & GameEvent } + */ + toPromise(){ + if(this.async&&this.resolve){ + throw new TypeError('This event has been converted into a promise'); + } + return new lib.element.GameEventPromise(this); + } + }, + GameEventPromise:class extends Promise{ + // 我谢谢你,这里是必须有的 + static get [Symbol.species]() { + return Promise; + } + /** + * @param { GameEvent } event + * @returns { Promise & GameEvent } + */ + constructor(event){ + super(resolve=>{ + // 设置为异步事件 + event.async=true; + // 事件结束后触发resolve + event.resolve=resolve; + //如果父级事件也是一个异步的话,那应该立即执行这个事件的 + if(_status.event.next.includes(event)&&_status.event.content instanceof AsyncFunction){ + // console.log(event, '的父级事件也是一个异步,立即执行这个事件'); + if (_status.event != event) { + event.parent = _status.event; + _status.event = event; + game.getGlobalHistory('everything').push(event); + } + game.loop(event); + } + }); + return new Proxy(this,{ + get(target,prop,receiver){ + const thisValue=Reflect.get(target,prop); + if(thisValue){ + if(typeof thisValue=='function') { + return thisValue.bind(target); + } + return thisValue; + } + const eventValue=Reflect.get(event,prop); + // 返回值如果是event,则修改为GameEventPromise + if(typeof eventValue=='function') return (function(...args){ + const returnValue=eventValue.call(event,...args); + return returnValue==event?receiver:returnValue; + }).bind(event); + return eventValue; + }, + set(target,prop,newValue){ + return Reflect.set(event,prop,newValue); + }, + deleteProperty(target,prop){ + return Reflect.set(event,prop); + }, + defineProperty(target,prop,attributes){ + return Reflect.defineProperty(event,prop,attributes); + }, + has(target,prop){ + return Reflect.has(event,prop); + }, + ownKeys(target,prop){ + return Reflect.ownKeys(event,prop); + }, + }); + } + /** + * TODO: 实现debugger + */ + async debugger(){ + return new Promise(resolve=>{ + resolve(null); + }); + } }, Dialog:class extends HTMLDivElement{ constructor(){ @@ -41263,217 +41372,222 @@ new Promise(resolve=>{ setTimeout(game.reload,15000) } }, - loop:function(){ - while(true){ - var event=_status.event; - var step=event.step; - var source=event.source; - var player=event.player; - var target=event.target; - var targets=event.targets; - var card=event.card; - var cards=event.cards; - var skill=event.skill; - var forced=event.forced; - var num=event.num; - var trigger=event._trigger; - var result=event._result; - if(_status.paused2||_status.imchoosing){ - if(!lib.status.dateDelaying){ - lib.status.dateDelaying=new Date(); + /** + * @param { GameEvent } [belongAsyncEvent] + */ + loop:function(belongAsyncEvent){ + if(belongAsyncEvent){ + game.belongAsyncEvent=belongAsyncEvent; + }else if(game.belongAsyncEvent){ + return game.loop(game.belongAsyncEvent); + } + return new Promise(async resolve=>{ + while(true){ + let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; + let { step, source, player, target, targets, card, cards, skill, forced, num, _trigger: trigger, _result: result } = event; + const _resolve=()=>{ + if(event.async){ + if(typeof event.resolve=='function'){ + event.resolve(event); + }else{ + throw new TypeError('异步事件的event.resolve未赋值,使用await时将会被永久等待'); + } + } + }; + if(_status.paused2||_status.imchoosing){ + if(!lib.status.dateDelaying){ + lib.status.dateDelaying=new Date(); + } } - } - if(_status.paused||_status.paused2||_status.over){ - return; - } - if(_status.paused3){ - _status.paused3='paused'; - return; - } - if(lib.status.dateDelaying){ - lib.status.dateDelayed+=lib.getUTC(new Date())-lib.getUTC(lib.status.dateDelaying); - delete lib.status.dateDelaying; - } - if(event.next.length>0){ - var next=event.next.shift(); - if(next.player&&next.player.skipList.contains(next.name)){ - event.trigger(next.name+'Skipped'); - next.player.skipList.remove(next.name); - if(lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name); + if(_status.paused||_status.paused2||_status.over){ + return; } - else{ - next.parent=event; - _status.event=next; - game.getGlobalHistory('everything').push(next); + if(_status.paused3){ + _status.paused3='paused'; + return; } - } - else if(event.finished){ - if(event._triggered==1){ - if(event.type=='card') event.trigger('useCardToOmitted'); - event.trigger(event.name+'Omitted'); - event._triggered=4; + if(lib.status.dateDelaying){ + lib.status.dateDelayed+=lib.getUTC(new Date())-lib.getUTC(lib.status.dateDelaying); + delete lib.status.dateDelaying; } - else if(event._triggered==2){ - if(event.type=='card') event.trigger('useCardToEnd'); - event.trigger(event.name+'End'); - event._triggered=3; + if (belongAsyncEvent) { + console.log('-----------------------'); + console.log(event); + console.log('event.finished', event.finished); + console.log('event.after:', [...event.after]); + console.log('event.next:', [...event.next]); } - else if(event._triggered==3){ - if(event.type=='card') event.trigger('useCardToAfter'); - event.trigger(event.name+'After'); - event._triggered++; - } - else if(event.after&&event.after.length){ - var next=event.after.shift(); + if(event.next.length>0){ + var next=event.next.shift(); if(next.player&&next.player.skipList.contains(next.name)){ event.trigger(next.name+'Skipped'); next.player.skipList.remove(next.name); - if(lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name) + if(lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name); } else{ next.parent=event; _status.event=next; + game.getGlobalHistory('everything').push(next); } } - else{ - if(event.parent){ - if(event.result){ - event.parent._result=event.result; - } - _status.event=event.parent; + else if(event.finished){ + if(event._triggered==1){ + if(event.type=='card') event.trigger('useCardToOmitted'); + event.trigger(event.name+'Omitted'); + event._triggered=4; } - else{ - return; + else if(event._triggered==2){ + if(event.type=='card') event.trigger('useCardToEnd'); + event.trigger(event.name+'End'); + event._triggered=3; } - } - } - else{ - if(event._triggered==0){ - if(event.type=='card') event.trigger('useCardToBefore'); - event.trigger(event.name+'Before'); - event._triggered++; - } - else if(event._triggered==1){ - if(event.type=='card') event.trigger('useCardToBegin'); - event.trigger(event.name+'Begin'); - event._triggered++; - /*if(event.name=='phase'&&!event._begun){ - var next=game.createEvent('phasing',false,event); - next.player=event.player; - next.skill=event.skill; - next.setContent('phasing'); - event._begun=true; - } - else{ - event.trigger(event.name+'Begin'); + else if(event._triggered==3){ + if(event.type=='card') event.trigger('useCardToAfter'); + event.trigger(event.name+'After'); event._triggered++; - }*/ - } - else{ - event.callHandler(event.getDefaultHandlerType(),event,{ - state:'begin' - }); - if(player&&player.classList.contains('dead')&&!event.forceDie&&event.name!='phaseLoop'){ - game.broadcastAll(function(){ - while(_status.dieClose.length){ - _status.dieClose.shift().close(); - } - }); - if(event._oncancel){ - event._oncancel(); - } - event.finish(); } - else if(player&&player.removed&&event.name!='phaseLoop'){ - event.finish(); - } - else if(player&&player.isOut()&&event.name!='phaseLoop'&&!event.includeOut){ - if(event.name=='phase'&&player==_status.roundStart&&!event.skill){ - _status.roundSkipped=true; + else if(event.after&&event.after.length){ + var next=event.after.shift(); + if(next.player&&next.player.skipList.contains(next.name)){ + event.trigger(next.name+'Skipped'); + next.player.skipList.remove(next.name); + if(lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name) + } + else{ + next.parent=event; + _status.event=next; } - event.finish(); } else{ - if(_status.withError||lib.config.compatiblemode||(_status.connectMode&&!lib.config.debug)){ - try{ - if(event.content instanceof GeneratorFunction){ - if(!event.debugging){ - if(event.generatorContent) event.generatorContent.return(); - event.generatorContent=event.content(event,step,source,player,target,targets, - card,cards,skill,forced,num,trigger,result, - _status,lib,game,ui,get,ai); - }else{ - delete event.debugging; - } - var next=event.generatorContent.next(); - if(typeof next.value=='function'&&next.value.toString()=='code=>eval(code)'){ - //触发debugger - var inputCallback=inputResult=>{ - if(inputResult===false){ - event.debugging=true; - game.resume2(); - }else{ - alert(get.stringify(next.value(inputResult))); - game.prompt('','debugger调试',inputCallback); - } - } - game.prompt('','debugger调试',inputCallback); - return game.pause2(); - } - if(event.finished) event.generatorContent.return(); - }else{ - event.content(event,step,source,player,target,targets, - card,cards,skill,forced,num,trigger,result, - _status,lib,game,ui,get,ai); - } + if(event.parent){ + if(event.result){ + event.parent._result=event.result; } - catch(e){ - game.print('游戏出错:'+event.name); - game.print(e.toString()); - console.log(e); + _status.event=event.parent; + if(game.belongAsyncEvent==event){ + delete game.belongAsyncEvent; + resolve(); + } + _resolve(); + // 此时应该退出了 + if (belongAsyncEvent && belongAsyncEvent.parent == _status.event){ + return; } } else{ - if(event.content instanceof GeneratorFunction){ - if(!event.debugging){ - if(event.generatorContent) event.generatorContent.return(); - event.generatorContent=event.content(event,step,source,player,target,targets, - card,cards,skill,forced,num,trigger,result, - _status,lib,game,ui,get,ai); - }else{ - delete event.debugging; - } - var next=event.generatorContent.next(); - if(typeof next.value=='function'&&next.value.toString()=='code=>eval(code)'){ - //触发debugger - var inputCallback=inputResult=>{ - if(inputResult===false){ - event.debugging=true; - game.resume2(); - }else{ - alert(get.stringify(next.value(inputResult))); - game.prompt('','debugger调试',inputCallback); - } - } - game.prompt('','debugger调试',inputCallback); - return game.pause2(); - } - if(event.finished) event.generatorContent.return(); - }else{ - event.content(event,step,source,player,target,targets, - card,cards,skill,forced,num,trigger,result, - _status,lib,game,ui,get,ai); + if(game.belongAsyncEvent==event){ + delete game.belongAsyncEvent; + resolve(); } + return _resolve(); + } + } + } + else{ + if(event._triggered==0){ + if(event.type=='card') event.trigger('useCardToBefore'); + event.trigger(event.name+'Before'); + event._triggered++; + } + else if(event._triggered==1){ + if(event.type=='card') event.trigger('useCardToBegin'); + event.trigger(event.name+'Begin'); + event._triggered++; + } + else{ + event.callHandler(event.getDefaultHandlerType(),event,{ + state:'begin' + }); + const after=()=>{ + event.clearStepCache(); + event.callHandler(event.getDefaultHandlerType(),event,{ + state:'end' + }); + if(typeof event.step=="number") ++event.step; + }; + if(player&&player.classList.contains('dead')&&!event.forceDie&&event.name!='phaseLoop'){ + game.broadcastAll(function(){ + while(_status.dieClose.length){ + _status.dieClose.shift().close(); + } + }); + if(event._oncancel){ + event._oncancel(); + } + event.finish(); + after(); + } + else if(player&&player.removed&&event.name!='phaseLoop'){ + event.finish(); + after(); + } + else if(player&&player.isOut()&&event.name!='phaseLoop'&&!event.includeOut){ + if(event.name=='phase'&&player==_status.roundStart&&!event.skill){ + _status.roundSkipped=true; + } + event.finish(); + after(); + } + else{ + await game.runContent(belongAsyncEvent).catch(e=>{ + if(_status.withError||lib.config.compatiblemode||(_status.connectMode&&!lib.config.debug)){ + game.print('游戏出错:'+event.name); + game.print(e.toString()); + console.log(e); + } + else throw e; + }).then(after); } } - event.clearStepCache(); - event.callHandler(event.getDefaultHandlerType(),event,{ - state:'end' - }); - if(typeof event.step=="number") ++event.step; } } - } + }); + }, + runContent(belongAsyncEvent) { + return new Promise(resolve=>{ + let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; + let { step, source, player, target, targets, card, cards, skill, forced, num, _trigger: trigger, _result: result } = event; + if (event.content instanceof GeneratorFunction) { + if (!event.debugging) { + if (event.generatorContent) event.generatorContent.return(); + event.generatorContent = event.content(event, step, source, player, target, targets, + card, cards, skill, forced, num, trigger, result, + _status, lib, game, ui, get, ai); + } else { + delete event.debugging; + } + var next = event.generatorContent.next(); + if (typeof next.value == 'function' && next.value.toString() == 'code=>eval(code)') { + //触发debugger + var inputCallback = inputResult => { + if (inputResult === false) { + event.debugging = true; + game.resume2(); + } else { + alert(get.stringify(next.value(inputResult))); + game.prompt('', 'debugger调试', inputCallback); + } + } + game.prompt('', 'debugger调试', inputCallback); + return game.pause2(); + } + if (event.finished) event.generatorContent.return(); + resolve(); + } + else if (event.content instanceof AsyncFunction) { + // _status,lib,game,ui,get,ai六个变量由game.import提供 + event.content(event, trigger, player).then(() => { + event.finish(); + resolve(); + }); + } + else { + event.content(event, step, source, player, target, targets, + card, cards, skill, forced, num, trigger, result, + _status, lib, game, ui, get, ai); + resolve(); + } + }); }, pause:function(){ clearTimeout(_status.timeout); From afbbc3cb3278e863c867be48ea9e74d19c2c8e4c Mon Sep 17 00:00:00 2001 From: shijian <2954700422@qq.com> Date: Wed, 6 Dec 2023 22:56:09 +0800 Subject: [PATCH 2/6] =?UTF-8?q?=E5=88=A0=E9=99=A4=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=97=A0=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- character/shenhua.js | 5 --- character/standard.js | 87 ++----------------------------------------- game/game.js | 8 ---- 3 files changed, 4 insertions(+), 96 deletions(-) diff --git a/character/shenhua.js b/character/shenhua.js index 90c8698e4..bad0c97ae 100755 --- a/character/shenhua.js +++ b/character/shenhua.js @@ -3952,13 +3952,8 @@ game.import('character',function(lib,game,ui,get,ai,_status){ if(target.isMin()) return false; return player!=target&&target.canEquip(card); }, - content2:function(){ - target.equip(cards[0]); - player.draw(); - }, async content(event, trigger, player){ await event.target.promises.equip(event.cards[0]); - game.log('老子装完了,还没摸牌') await player.promises.draw(); }, discard:false, diff --git a/character/standard.js b/character/standard.js index ec99b9c47..ed9023aaf 100755 --- a/character/standard.js +++ b/character/standard.js @@ -588,90 +588,16 @@ game.import('character',function(lib,game,ui,get,ai,_status){ filter:function(event){ return (event.num>0) }, - content2:function(){ - 'step 0' - event.count=trigger.num; - 'step 1' - event.count--; - event.cards=game.cardsGotoOrdering(get.cards(2)).cards; - if(_status.connectMode) game.broadcastAll(function(){_status.noclearcountdown=true}); - event.given_map={}; - 'step 2' - if(event.cards.length>1){ - player.chooseCardButton('遗计:请选择要分配的牌',true,event.cards,[1,event.cards.length]).set('ai',function(button){ - if(ui.selected.buttons.length==0) return 1; - return 0; - }); - } - else if(event.cards.length==1){ - event._result={links:event.cards.slice(0),bool:true}; - } - else{ - event.finish(); - } - 'step 3' - if(result.bool){ - event.cards.removeArray(result.links); - event.togive=result.links.slice(0); - player.chooseTarget('选择一名角色获得'+get.translation(result.links),true).set('ai',function(target){ - var att=get.attitude(_status.event.player,target); - if(_status.event.enemy){ - return -att; - } - else if(att>0){ - return att/(1+target.countCards('h')); - } - else{ - return att/100; - } - }).set('enemy',get.value(event.togive[0],player,'raw')<0); - } - 'step 4' - if(result.targets.length){ - var id=result.targets[0].playerid,map=event.given_map; - if(!map[id]) map[id]=[]; - map[id].addArray(event.togive); - } - if(cards.length>0) event.goto(2); - 'step 5' - if(_status.connectMode){ - game.broadcastAll(function(){delete _status.noclearcountdown;game.stopCountChoose()}); - } - var list=[]; - for(var i in event.given_map){ - var source=(_status.connectMode?lib.playerOL:game.playerMap)[i]; - player.line(source,'green'); - list.push([source,event.given_map[i]]); - } - game.loseAsync({ - gain_list:list, - giver:player, - animate:'draw', - }).setContent('gaincardMultiple'); - 'step 6' - if(event.count>0&&player.hasSkill(event.name)&&!get.is.blocked(event.name,player)){ - player.chooseBool(get.prompt2(event.name)).set('frequentSkill',event.name); - } - else event.finish(); - 'step 7' - if(result.bool){ - player.logSkill(event.name); - event.goto(1); - } - }, async content(event, trigger, player) { - console.log('step 0'); event.count = trigger.num; while (event.count > 0) { - console.log('step 1'); event.count--; const { cards } = await game.cardsGotoOrdering(get.cards(2)).toPromise(); if (_status.connectMode) game.broadcastAll(function () { _status.noclearcountdown = true }); event.given_map = {}; - if (!cards.length) return event.finish(); + if (!cards.length) return; do { - console.log('step 2'); const { result: { bool, links } } = cards.length == 1 ? { result: { links: cards.slice(0), bool: true } } : @@ -680,8 +606,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ if (ui.selected.buttons.length == 0) return 1; return 0; }); - if (!bool) return event.finish(); - console.log('step 3'); + if (!bool) return; cards.removeArray(links); event.togive = links.slice(0); const { result: { targets } } = await player.promises.chooseTarget('选择一名角色获得' + get.translation(links), true) @@ -698,7 +623,6 @@ game.import('character',function(lib,game,ui,get,ai,_status){ } }) .set('enemy', get.value(event.togive[0], player, 'raw') < 0); - console.log('step 4'); if (targets.length) { const id = targets[0].playerid, map = event.given_map; @@ -706,7 +630,6 @@ game.import('character',function(lib,game,ui,get,ai,_status){ map[id].addArray(event.togive); } } while (cards.length > 0); - console.log('step 5'); if (_status.connectMode) { game.broadcastAll(function () { delete _status.noclearcountdown; game.stopCountChoose() }); } @@ -721,15 +644,13 @@ game.import('character',function(lib,game,ui,get,ai,_status){ giver: player, animate: 'draw', }).setContent('gaincardMultiple').toPromise(); - console.log('step 6'); if (event.count > 0 && player.hasSkill(event.name) && !get.is.blocked(event.name, player)) { const { result: { bool: repeat } } = await player.promises.chooseBool(get.prompt2(event.name)).set('frequentSkill', event.name); - console.log('step 7'); if (repeat) { player.logSkill(event.name); - } + } else return; } - else return event.finish(); + else return; } }, ai:{ diff --git a/game/game.js b/game/game.js index 45e204a9b..f1c7385e7 100644 --- a/game/game.js +++ b/game/game.js @@ -32131,7 +32131,6 @@ new Promise(resolve=>{ event.resolve=resolve; //如果父级事件也是一个异步的话,那应该立即执行这个事件的 if(_status.event.next.includes(event)&&_status.event.content instanceof AsyncFunction){ - // console.log(event, '的父级事件也是一个异步,立即执行这个事件'); if (_status.event != event) { event.parent = _status.event; _status.event = event; @@ -41410,13 +41409,6 @@ new Promise(resolve=>{ lib.status.dateDelayed+=lib.getUTC(new Date())-lib.getUTC(lib.status.dateDelaying); delete lib.status.dateDelaying; } - if (belongAsyncEvent) { - console.log('-----------------------'); - console.log(event); - console.log('event.finished', event.finished); - console.log('event.after:', [...event.after]); - console.log('event.next:', [...event.next]); - } if(event.next.length>0){ var next=event.next.shift(); if(next.player&&next.player.skipList.contains(next.name)){ From 7d64a0629d508531d211014c2dfb655d8c635c13 Mon Sep 17 00:00:00 2001 From: shijian <2954700422@qq.com> Date: Wed, 6 Dec 2023 23:00:07 +0800 Subject: [PATCH 3/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- character/standard.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/character/standard.js b/character/standard.js index ed9023aaf..2afcae560 100755 --- a/character/standard.js +++ b/character/standard.js @@ -586,17 +586,18 @@ game.import('character',function(lib,game,ui,get,ai,_status){ trigger:{player:'damageEnd'}, frequent:true, filter:function(event){ - return (event.num>0) + return event.num>0; }, async content(event, trigger, player) { event.count = trigger.num; + // event.goto -> while while (event.count > 0) { event.count--; const { cards } = await game.cardsGotoOrdering(get.cards(2)).toPromise(); if (_status.connectMode) game.broadcastAll(function () { _status.noclearcountdown = true }); event.given_map = {}; - if (!cards.length) return; + // event.goto -> do while do { const { result: { bool, links } } = cards.length == 1 ? From 4edcc6f0c59f78900d8c896399dbeb3773ddbd41 Mon Sep 17 00:00:00 2001 From: shijian <2954700422@qq.com> Date: Thu, 7 Dec 2023 14:01:52 +0800 Subject: [PATCH 4/6] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=B3=A8=E9=87=8A=EF=BC=8C=E4=BF=AE=E5=A4=8DtoPromise=E7=AB=8B?= =?UTF-8?q?=E5=8D=B3=E6=89=A7=E8=A1=8C=E6=89=80=E5=AF=BC=E8=87=B4=E7=9A=84?= =?UTF-8?q?=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- character/standard.js | 2 +- game/game.js | 318 +++++++++++++++++++++++------------------- 2 files changed, 172 insertions(+), 148 deletions(-) diff --git a/character/standard.js b/character/standard.js index 2afcae560..6308d4dff 100755 --- a/character/standard.js +++ b/character/standard.js @@ -644,7 +644,7 @@ game.import('character',function(lib,game,ui,get,ai,_status){ gain_list: list, giver: player, animate: 'draw', - }).setContent('gaincardMultiple').toPromise(); + }).toPromise().setContent('gaincardMultiple'); if (event.count > 0 && player.hasSkill(event.name) && !get.is.blocked(event.name, player)) { const { result: { bool: repeat } } = await player.promises.chooseBool(get.prompt2(event.name)).set('frequentSkill', event.name); if (repeat) { diff --git a/game/game.js b/game/game.js index f1c7385e7..95f0b0150 100644 --- a/game/game.js +++ b/game/game.js @@ -32104,7 +32104,6 @@ new Promise(resolve=>{ /** * 事件转为Promise化 * - * 注: 该函数在async content中执行时,必须在所有setxx函数执行后执行。 * @returns { Promise & GameEvent } */ toPromise(){ @@ -32114,8 +32113,30 @@ new Promise(resolve=>{ return new lib.element.GameEventPromise(this); } }, + /** + * 对于事件Promise化后,需要既能使用await等待事件完成, + * 又需要在执行之前对事件进行配置。 + * + * 所以这个类的实例集成了事件和Promise二者的所有属性, + * 且Promise的原有属性无法被修改,一切对这个类实例的属性修改,删除, + * 再配置等操作都会转发到事件对应的属性中。 + * + * @todo 需要完成异步事件的debugger方法 + * + * @example + * 使用toPromise()函数将普通事件转换为异步事件: + * ```js + * await game.xxx().toPromise().setContent('yyy').set(zzz, 'i'); + * ``` + * 使用player.promises.xxx()函数将对于player的普通事件转换为异步事件: + * ```js + * await player.draw(2); + * game.log('等待', player, '摸牌完成执行log'); + * ``` + */ GameEventPromise:class extends Promise{ // 我谢谢你,这里是必须有的 + // 否则Promise的方法对其子类无效 static get [Symbol.species]() { return Promise; } @@ -32129,27 +32150,32 @@ new Promise(resolve=>{ event.async=true; // 事件结束后触发resolve event.resolve=resolve; - //如果父级事件也是一个异步的话,那应该立即执行这个事件的 + // 如果父级事件也是一个异步的话,那应该立即执行这个事件的 + // 如果在AsyncFunction执行过程中在别的位置新建了一个异步事件,那也直接(等会set配置完)执行 if(_status.event.next.includes(event)&&_status.event.content instanceof AsyncFunction){ - if (_status.event != event) { - event.parent = _status.event; - _status.event = event; + if (_status.event!=event) { + event.parent=_status.event; + _status.event=event; game.getGlobalHistory('everything').push(event); } - game.loop(event); + // 异步执行game.loop + // 不直接game.loop(event)是因为需要让别人可以手动set()和setContent() + // 再执行game.loop是因为原有的game.loop被await卡住了, + // 得新执行一个只执行这个异步事件的game.loop + Promise.resolve().then(()=>game.loop(event)); } }); return new Proxy(this,{ get(target,prop,receiver){ const thisValue=Reflect.get(target,prop); if(thisValue){ - if(typeof thisValue=='function') { + if(typeof thisValue=='function'){ return thisValue.bind(target); } return thisValue; } const eventValue=Reflect.get(event,prop); - // 返回值如果是event,则修改为GameEventPromise + // 返回值如果是event,则修改为GameEventPromise类实例 if(typeof eventValue=='function') return (function(...args){ const returnValue=eventValue.call(event,...args); return returnValue==event?receiver:returnValue; @@ -41374,166 +41400,164 @@ new Promise(resolve=>{ /** * @param { GameEvent } [belongAsyncEvent] */ - loop:function(belongAsyncEvent){ + async loop(belongAsyncEvent){ if(belongAsyncEvent){ game.belongAsyncEvent=belongAsyncEvent; }else if(game.belongAsyncEvent){ return game.loop(game.belongAsyncEvent); } - return new Promise(async resolve=>{ - while(true){ - let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; - let { step, source, player, target, targets, card, cards, skill, forced, num, _trigger: trigger, _result: result } = event; - const _resolve=()=>{ - if(event.async){ - if(typeof event.resolve=='function'){ - event.resolve(event); - }else{ - throw new TypeError('异步事件的event.resolve未赋值,使用await时将会被永久等待'); - } - } - }; - if(_status.paused2||_status.imchoosing){ - if(!lib.status.dateDelaying){ - lib.status.dateDelaying=new Date(); + while (true) { + let event = (belongAsyncEvent && belongAsyncEvent.parent == _status.event) ? belongAsyncEvent : _status.event; + let { step, source, player, target, targets, card, cards, skill, forced, num, _trigger: trigger, _result: result } = event; + const _resolve = () => { + if (event.async) { + if (typeof event.resolve == 'function') { + event.resolve(event); + } else { + throw new TypeError('异步事件的event.resolve未赋值,使用await时将会被永久等待'); } } - if(_status.paused||_status.paused2||_status.over){ - return; + }; + if (_status.paused2 || _status.imchoosing) { + if (!lib.status.dateDelaying) { + lib.status.dateDelaying = new Date(); } - if(_status.paused3){ - _status.paused3='paused'; - return; + } + if (_status.paused || _status.paused2 || _status.over) { + return; + } + if (_status.paused3) { + _status.paused3 = 'paused'; + return; + } + if (lib.status.dateDelaying) { + lib.status.dateDelayed += lib.getUTC(new Date()) - lib.getUTC(lib.status.dateDelaying); + delete lib.status.dateDelaying; + } + if (event.next.length > 0) { + var next = event.next.shift(); + if (next.player && next.player.skipList.contains(next.name)) { + event.trigger(next.name + 'Skipped'); + next.player.skipList.remove(next.name); + if (lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name); } - if(lib.status.dateDelaying){ - lib.status.dateDelayed+=lib.getUTC(new Date())-lib.getUTC(lib.status.dateDelaying); - delete lib.status.dateDelaying; + else { + next.parent = event; + _status.event = next; + game.getGlobalHistory('everything').push(next); } - if(event.next.length>0){ - var next=event.next.shift(); - if(next.player&&next.player.skipList.contains(next.name)){ - event.trigger(next.name+'Skipped'); + } + else if (event.finished) { + if (event._triggered == 1) { + if (event.type == 'card') event.trigger('useCardToOmitted'); + event.trigger(event.name + 'Omitted'); + event._triggered = 4; + } + else if (event._triggered == 2) { + if (event.type == 'card') event.trigger('useCardToEnd'); + event.trigger(event.name + 'End'); + event._triggered = 3; + } + else if (event._triggered == 3) { + if (event.type == 'card') event.trigger('useCardToAfter'); + event.trigger(event.name + 'After'); + event._triggered++; + } + else if (event.after && event.after.length) { + var next = event.after.shift(); + if (next.player && next.player.skipList.contains(next.name)) { + event.trigger(next.name + 'Skipped'); next.player.skipList.remove(next.name); - if(lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name); + if (lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name) } - else{ - next.parent=event; - _status.event=next; - game.getGlobalHistory('everything').push(next); + else { + next.parent = event; + _status.event = next; } } - else if(event.finished){ - if(event._triggered==1){ - if(event.type=='card') event.trigger('useCardToOmitted'); - event.trigger(event.name+'Omitted'); - event._triggered=4; - } - else if(event._triggered==2){ - if(event.type=='card') event.trigger('useCardToEnd'); - event.trigger(event.name+'End'); - event._triggered=3; - } - else if(event._triggered==3){ - if(event.type=='card') event.trigger('useCardToAfter'); - event.trigger(event.name+'After'); - event._triggered++; - } - else if(event.after&&event.after.length){ - var next=event.after.shift(); - if(next.player&&next.player.skipList.contains(next.name)){ - event.trigger(next.name+'Skipped'); - next.player.skipList.remove(next.name); - if(lib.phaseName.contains(next.name)) next.player.getHistory('skipped').add(next.name) + else { + if (event.parent) { + if (event.result) { + event.parent._result = event.result; } - else{ - next.parent=event; - _status.event=next; + _status.event = event.parent; + if (game.belongAsyncEvent == event) { + delete game.belongAsyncEvent; + //resolve(); + } + _resolve(); + // 此时应该退出了 + if (belongAsyncEvent && belongAsyncEvent.parent == _status.event) { + return; } } - else{ - if(event.parent){ - if(event.result){ - event.parent._result=event.result; - } - _status.event=event.parent; - if(game.belongAsyncEvent==event){ - delete game.belongAsyncEvent; - resolve(); - } - _resolve(); - // 此时应该退出了 - if (belongAsyncEvent && belongAsyncEvent.parent == _status.event){ - return; - } - } - else{ - if(game.belongAsyncEvent==event){ - delete game.belongAsyncEvent; - resolve(); - } - return _resolve(); - } - } - } - else{ - if(event._triggered==0){ - if(event.type=='card') event.trigger('useCardToBefore'); - event.trigger(event.name+'Before'); - event._triggered++; - } - else if(event._triggered==1){ - if(event.type=='card') event.trigger('useCardToBegin'); - event.trigger(event.name+'Begin'); - event._triggered++; - } - else{ - event.callHandler(event.getDefaultHandlerType(),event,{ - state:'begin' - }); - const after=()=>{ - event.clearStepCache(); - event.callHandler(event.getDefaultHandlerType(),event,{ - state:'end' - }); - if(typeof event.step=="number") ++event.step; - }; - if(player&&player.classList.contains('dead')&&!event.forceDie&&event.name!='phaseLoop'){ - game.broadcastAll(function(){ - while(_status.dieClose.length){ - _status.dieClose.shift().close(); - } - }); - if(event._oncancel){ - event._oncancel(); - } - event.finish(); - after(); - } - else if(player&&player.removed&&event.name!='phaseLoop'){ - event.finish(); - after(); - } - else if(player&&player.isOut()&&event.name!='phaseLoop'&&!event.includeOut){ - if(event.name=='phase'&&player==_status.roundStart&&!event.skill){ - _status.roundSkipped=true; - } - event.finish(); - after(); - } - else{ - await game.runContent(belongAsyncEvent).catch(e=>{ - if(_status.withError||lib.config.compatiblemode||(_status.connectMode&&!lib.config.debug)){ - game.print('游戏出错:'+event.name); - game.print(e.toString()); - console.log(e); - } - else throw e; - }).then(after); + else { + if (game.belongAsyncEvent == event) { + delete game.belongAsyncEvent; + //resolve(); } + return _resolve(); } } } - }); + else { + if (event._triggered == 0) { + if (event.type == 'card') event.trigger('useCardToBefore'); + event.trigger(event.name + 'Before'); + event._triggered++; + } + else if (event._triggered == 1) { + if (event.type == 'card') event.trigger('useCardToBegin'); + event.trigger(event.name + 'Begin'); + event._triggered++; + } + else { + event.callHandler(event.getDefaultHandlerType(), event, { + state: 'begin' + }); + const after = () => { + event.clearStepCache(); + event.callHandler(event.getDefaultHandlerType(), event, { + state: 'end' + }); + if (typeof event.step == "number") ++event.step; + }; + if (player && player.classList.contains('dead') && !event.forceDie && event.name != 'phaseLoop') { + game.broadcastAll(function () { + while (_status.dieClose.length) { + _status.dieClose.shift().close(); + } + }); + if (event._oncancel) { + event._oncancel(); + } + event.finish(); + after(); + } + else if (player && player.removed && event.name != 'phaseLoop') { + event.finish(); + after(); + } + else if (player && player.isOut() && event.name != 'phaseLoop' && !event.includeOut) { + if (event.name == 'phase' && player == _status.roundStart && !event.skill) { + _status.roundSkipped = true; + } + event.finish(); + after(); + } + else { + await game.runContent(belongAsyncEvent).catch(e => { + if (_status.withError || lib.config.compatiblemode || (_status.connectMode && !lib.config.debug)) { + game.print('游戏出错:' + event.name); + game.print(e.toString()); + console.log(e); + } + else throw e; + }).then(after); + } + } + } + } }, runContent(belongAsyncEvent) { return new Promise(resolve=>{ From f09a898ac96607f5880a5e8c1b2b5dee557ffe51 Mon Sep 17 00:00:00 2001 From: shijian <2954700422@qq.com> Date: Thu, 7 Dec 2023 14:12:23 +0800 Subject: [PATCH 5/6] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/game.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/game/game.js b/game/game.js index 95f0b0150..4626db53d 100644 --- a/game/game.js +++ b/game/game.js @@ -32114,7 +32114,9 @@ new Promise(resolve=>{ } }, /** - * 对于事件Promise化后,需要既能使用await等待事件完成, + * 将事件Promise化以使用async异步函数来执行事件。 + * + * 事件Promise化后,需要既能使用await等待事件完成, * 又需要在执行之前对事件进行配置。 * * 所以这个类的实例集成了事件和Promise二者的所有属性, @@ -32128,9 +32130,9 @@ new Promise(resolve=>{ * ```js * await game.xxx().toPromise().setContent('yyy').set(zzz, 'i'); * ``` - * 使用player.promises.xxx()函数将对于player的普通事件转换为异步事件: + * 使用player.promises.xxx()函数将对于player的普通事件转换为异步事件并执行: * ```js - * await player.draw(2); + * await player.promises.draw(2); * game.log('等待', player, '摸牌完成执行log'); * ``` */ From 8a132614003ff3dd7993b54b45ea2d72cbe35ad1 Mon Sep 17 00:00:00 2001 From: shijian <2954700422@qq.com> Date: Thu, 7 Dec 2023 14:43:19 +0800 Subject: [PATCH 6/6] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=B8=80=E5=A4=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/game.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/game/game.js b/game/game.js index 4626db53d..818105c53 100644 --- a/game/game.js +++ b/game/game.js @@ -32188,7 +32188,7 @@ new Promise(resolve=>{ return Reflect.set(event,prop,newValue); }, deleteProperty(target,prop){ - return Reflect.set(event,prop); + return Reflect.deleteProperty(event,prop); }, defineProperty(target,prop,attributes){ return Reflect.defineProperty(event,prop,attributes);