webxoss-core/Game.js

1133 lines
32 KiB
JavaScript
Raw Permalink Normal View History

2016-10-23 07:56:45 +02:00
'use strict';
function Game (cfg) {
// 基本属性
this.seed = cfg.seed;
this.onGameover = cfg.onGameover;
this.winner = null;
this.cards = [];
// 私有
this._r = new Random(Random.engines.mt19937().seed(cfg.seed));
this._frameCount = 0;
this._sources = [];
this._framedBeforeBlock = false; // 表示处理块前,是否有帧发生.
// 在驱逐力量0以下的 SIGNI 前置 false, 在 handleFrameEnd() 中置 true.
// 因为第一次驱逐力量0以下的 SIGNI 后,可能发生常时效果改变,
// 导致剩下的 SIGNI 力量也变为0以下.
// 于是不断驱逐力量0以下的 SIGNI 直至 _framedBeforeBlock 为 false.
// 储存的数据
this.objList = [];
this.hostMsgObjs = [];
this.guestMsgObjs = [];
this.dataObj = {}; // 储存游戏对象(card,player 等)绑定的数据,回合结束时清空
this.trashingCards = [];
this.trashingCharms = [];
2016-10-23 07:56:45 +02:00
// 注册
this.register(this);
// 玩家
this.hostPlayer = new Player(this,cfg.hostIO,cfg.hostMainDeck,cfg.hostLrigDeck);
this.guestPlayer = new Player(this,cfg.guestIO,cfg.guestMainDeck,cfg.guestLrigDeck);
this.hostPlayer.opponent = this.guestPlayer;
this.guestPlayer.opponent = this.hostPlayer;
this.turnPlayer = this.hostPlayer;
// 组件
this.phase = new Phase(this);
this.constEffectManager = new ConstEffectManager(this);
this.effectManager = new EffectManager(this);
this.triggeringEffects = [];
this.triggeringEvents = [];
// 附加属性
this.trashWhenPowerBelowZero = false;
this.spellToCutIn = null; // <ブルー・パニッシュ>
};
Game.checkDeck = function (cfg,mayusRoom) {
if (!isObj(cfg)) return false;
if (!isArr(cfg.mainDeck) || !isArr(cfg.lrigDeck)) return false;
// 主卡组正好40张
if (cfg.mainDeck.length !== 40) return false;
// LRIG卡组最多10张
if (cfg.lrigDeck.length > 10) return false;
// toInfo
var mainDeckInfos = [];
var lrigDeckInfos = [];
var burstCount = 0;
var flagLrig = false;
for (var i = 0; i < cfg.mainDeck.length; i++) {
var pid = cfg.mainDeck[i];
var info = CardInfo[pid];
if (!info) return false;
info = CardInfo[info.cid];
if (!info) return false;
if (info.cardType === 'LRIG') return false;
if (info.cardType === 'ARTS') return false;
if (info.cardType === 'RESONA') return false;
if (info.burstEffect) {
burstCount++;
}
mainDeckInfos.push(info);
}
for (var i = 0; i < cfg.lrigDeck.length; i++) {
var pid = cfg.lrigDeck[i];
var info = CardInfo[pid];
if (!info) return false;
info = CardInfo[info.cid];
if (!info) return false;
if (info.cardType === 'SIGNI') return false;
if (info.cardType === 'SPELL') return false;
if ((info.cardType === 'LRIG') && (info.level === 0)) {
flagLrig = true;
}
lrigDeckInfos.push(info);
}
var infos = mainDeckInfos.concat(lrigDeckInfos);
// LRIG卡组至少有一张0级LRIG
if (!flagLrig) return false;
// 生命迸发恰好20张
if (burstCount !== 20) return false;
// 相同的卡最多放入4张
var legal = [mainDeckInfos,lrigDeckInfos].every(function (infos) {
var bucket = {};
infos.forEach(function (info) {
2016-12-02 18:09:52 +01:00
if (info.sideA) {
info = CardInfo[info.sideA]
}
2016-10-23 07:56:45 +02:00
if (info.cid in bucket) {
bucket[info.cid]++;
} else {
bucket[info.cid] = 1;
}
});
for (var cid in bucket) {
if (bucket[cid] > 4) return false;
}
return true;
},this);
if (!legal) return false;
if (!mayusRoom) return true;
return Game.checkMayusRoom(infos);
};
Game.checkMayusRoom = function (infos) {
// 禁止 狐狸+修复 和 狐狸+Three out
if (infos.some(function (info) {
return info.cid === 33; // 狐狸
}) && infos.some(function (info) {
return (info.cid === 34) || (info.cid === 84); // 修复, three out
})) {
return false;
}
// 禁止 V・・C+共鸣・进军 和 V・・C+共鸣
if (infos.some(function (info) {
return info.cid === 1202; // V・・C
}) && infos.some(function (info) {
return (info.cid === 884) || (info.cid === 1369); // 共鸣・进军, 共鸣
})) {
return false;
}
// 禁止 Lock+割裂 和 Lock+精挖
if (infos.some(function (info) {
return info.cid === 534; // Lock
}) && infos.some(function (info) {
return (info.cid === 408) || (info.cid === 570); // 割裂, 精挖
})) {
return false;
}
// 禁止 Ar+魔术手
if (infos.some(function (info) {
return info.cid === 814; // Ar
}) && infos.some(function (info) {
return (info.cid === 1090); // 魔术手
})) {
return false;
}
// 禁止 双麻油
if (infos.some(function (info) {
return info.cid === 649; // 創世の巫女 マユ
}) && infos.some(function (info) {
return (info.cid === 1562); // 真名の巫女 マユ
})) {
return false;
}
2016-12-02 17:57:06 +01:00
// 禁止 台风蛇
if (infos.some(function (info) {
return info.cid === 957; // 台風一過
}) && infos.some(function (info) {
return (info.cid === 1652); // コードアンシエンツ ヘルボロス
})) {
return false;
}
2016-10-23 07:56:45 +02:00
// 限制
var limitMap = {
37: 2, // <忘得ぬ幻想 ヴァルキリー>
34: 2, // <修復>
178: 2, // <先駆の大天使 アークゲイン>
2017-05-09 17:54:13 +02:00
1501: 2, // <幻竜 アパト>
2016-10-23 07:56:45 +02:00
534: 1, // <ロック・ユー>
2016-12-10 07:29:45 +01:00
// 689: 1, // <>
2016-10-23 07:56:45 +02:00
474: 0, // <ノー・ゲイン>
23: 0, // <大器晩成>
2016-12-02 17:57:06 +01:00
689: 0, // <>
1030: 0, // <四面楚火>
1457: 0, // <サーバント Z>
2017-05-09 17:54:13 +02:00
1212: 0, // <コードアート C・L>
2016-10-23 07:56:45 +02:00
};
for (var i = 0; i < infos.length; i++) {
var info = infos[i];
var cid = info.cid;
if (cid in limitMap) {
limitMap[cid]--;
if (limitMap[cid] < 0) return false;
}
}
return true;
};
Game.prototype.start = function () {
this.allocateSid(this.hostPlayer,this.objList);
this.allocateSid(this.guestPlayer,this.objList);
this.setupEffects();
this.outputInitMsg(this.hostPlayer);
this.outputInitMsg(this.guestPlayer);
this.phase.setup();
this.sendMsgQueue();
};
Game.prototype.setupEffects = function () {
[this.hostPlayer,this.guestPlayer].forEach(function (player) {
concat(player.mainDeck.cards,player.lrigDeck.cards).forEach(function (card) {
card.setupEffects();
},this);
},this);
};
Game.prototype.outputInitMsg = function (player) {
var opponent = player.opponent;
player.output({
type: 'INIT',
content: {
player: player,
opponent: opponent,
playerZones: {
mainDeck: player.mainDeck,
lrigDeck: player.lrigDeck,
handZone: player.handZone,
lrigZone: player.lrigZone,
signiZones: player.signiZones,
enerZone: player.enerZone,
checkZone: player.checkZone,
trashZone: player.trashZone,
lrigTrashZone: player.lrigTrashZone,
lifeClothZone: player.lifeClothZone,
excludedZone: player.excludedZone,
mainDeckCards: player.mainDeck.cards,
lrigDeckCards: player.lrigDeck.cards,
2016-10-25 13:41:19 +02:00
lrigDeckCardInfos: player.lrigDeck.cards.map(function (card) {
return {
pid: card.pid,
2016-11-12 10:08:56 +01:00
isSide: !!card.sideA
2016-10-25 13:41:19 +02:00
}
2016-10-23 07:56:45 +02:00
},this)
},
opponentZones: {
mainDeck: opponent.mainDeck,
lrigDeck: opponent.lrigDeck,
handZone: opponent.handZone,
lrigZone: opponent.lrigZone,
signiZones: opponent.signiZones,
enerZone: opponent.enerZone,
checkZone: opponent.checkZone,
trashZone: opponent.trashZone,
lrigTrashZone: opponent.lrigTrashZone,
lifeClothZone: opponent.lifeClothZone,
excludedZone: opponent.excludedZone,
mainDeckCards: opponent.mainDeck.cards,
lrigDeckCards: opponent.lrigDeck.cards,
2016-11-12 10:08:56 +01:00
lrigDeckCardInfos: opponent.lrigDeck.cards.map(function (card) {
2016-10-25 13:41:19 +02:00
return {
pid: 0,
2016-11-12 10:08:56 +01:00
isSide: !!card.sideA
2016-10-25 13:41:19 +02:00
}
2016-10-23 07:56:45 +02:00
},this)
}
}
});
};
Game.prototype.register = function (obj) {
if (!obj) throw new TypeError();
obj.gid = obj._asid = obj._bsid = this.objList.push(obj);
};
Game.prototype.allocateSid = function (player,objs) {
var len = objs.length;
objs.forEach(function (obj,i) {
var r = this.rand(i,len-1);
if ((player === this.hostPlayer)) {
var tmp = obj._asid;
obj._asid = objs[r]._asid;
objs[r]._asid = tmp;
} else {
var tmp = obj._bsid;
obj._bsid = objs[r]._bsid;
objs[r]._bsid = tmp;
}
},this);
};
Game.prototype.getSid = function (player,obj) {
return (player === this.hostPlayer)? obj._asid : obj._bsid;
};
Game.prototype.setSid = function (player,obj,sid) {
if (player === this.hostPlayer) {
obj._asid = sid;
} else {
obj._bsid = sid;
}
};
Game.prototype.getObjectBySid = function (player,sid) {
if (!isNum(sid)) return null;
for (var i = this.objList.length - 1; i >= 0; i--) {
var obj = this.objList[i];
if (player === this.hostPlayer) {
if (obj._asid === sid) return obj;
} else {
if (obj._bsid === sid) return obj;
}
}
return null;
};
Game.prototype.decideFirstPlayerAsyn = function () {
return Callback.immediately().callback(this,function () {
var firstPlayer = this.rand(0,1)? this.hostPlayer : this.guestPlayer;
return firstPlayer;
});
// var a,b;
// return this.hostPlayer.rockPaperScissorsAsyn(this,function (v) {
// a = v;
// }).callback(this,function () {
// return this.guestPlayer.rockPaperScissorsAsyn(this,function (v) {
// b = v;
// });
// }).callback(this,function () {
// if (a === b) return this.decideFirstPlayerAsyn();
// var aWin =
// ((a === 0) && (b === 2)) ||
// ((a === 1) && (b === 0)) ||
// ((a === 2) && (b === 2));
// var firstPlayer = aWin? this.hostPlayer : this.guestPlayer;
// return firstPlayer;
// });
};
Game.prototype.win = function (player) {
if (player.opponent.wontLoseGame) return false;
player.output({
type: 'WIN',
content: {}
});
player.opponent.output({
type: 'LOSE',
content: {}
});
this.winner = player;
return true;
};
Game.prototype.destroy = function () {
this.hostPlayer.io.listener = null;
this.guestPlayer.io.listener = null;
};
Game.prototype.output = function (msgObj) {
this.hostPlayer.output(msgObj);
this.guestPlayer.output(msgObj);
};
Game.prototype.packOutputs = function (func,thisp) {
this.output({
type: 'PACKED_MSG_START',
content: {}
});
var rtn = func.call(thisp || this);
this.output({
type: 'PACKED_MSG_END',
content: {}
});
return rtn;
};
Game.prototype.outputColor = function () {
var playerColor = this.turnPlayer.lrig.color;
var opponentColor = this.turnPlayer.opponent.lrig.color;
if (playerColor === 'colorless') {
playerColor = 'white';
}
if (opponentColor === 'colorless') {
opponentColor = 'white';
}
this.turnPlayer.output({
type: 'SET_COLOR',
content: {
selfColor: playerColor,
opponentColor: opponentColor
}
});
this.turnPlayer.opponent.output({
type: 'SET_COLOR',
content: {
selfColor: opponentColor,
opponentColor: playerColor
}
});
};
Game.prototype.sendMsgQueue = function () {
this.hostPlayer.sendMsgQueue();
this.guestPlayer.sendMsgQueue();
};
Game.prototype.rand = function (min,max) {
// return Math.floor(Math.random() * (max+1-min)) + min;
return this._r.integer(min,max);
};
Game.prototype.moveCards = function (cards,zone,arg) {
if (!cards.length) return [];
cards = cards.slice();
this.packOutputs(function () {
this.frameStart();
cards = cards.filter(function (card) {
return card.moveTo(zone,arg);
},this);
this.frameEnd();
});
return cards;
};
Game.prototype.moveCardsAdvancedAsyn = function (cards,zones,args,force) {
cards = cards.slice();
this.frameStart();
var source = this.getEffectSource();
var signis = []; // 可以被保护的 SIGNI
var protectedSignis = []; // 确实被保护了的 SIGNI
var succs = []; // 返回值,表示是否成功移动. 注: 被保护了也算成功移动.
var protectedFlags = []; // 返回值,表示是否被保护
if (!force && source && !source.powerChangeBanned) { // <幻兽神 狮王>
// 获得以被保护的 SIGNI
signis = cards.filter(function (card,i) {
return card.protectingShironakujis.length &&
(source.player === card.player.opponent) &&
inArr(card,card.player.signis) &&
!card.isEffectFiltered(source);
},this);
}
return Callback.forEach(signis,function (signi) {
// 获得保护该 SIGNI 的<幻水 蓝鲸>
var protectingShironakujis = signi.protectingShironakujis;
if (!protectingShironakujis.length) return;
return signi.player.selectOptionalAsyn('PROTECT',[signi]).callback(this,function (c) {
if (!c) return;
signi.beSelectedAsTarget();
return signi.player.selectOptionalAsyn('_SHIRONAKUJI',protectingShironakujis).callback(this,function (shironakuji) {
if (!shironakuji) return;
shironakuji.beSelectedAsTarget();
// 保护
protectedSignis.push(signi);
this.tillTurnEndAdd(source,shironakuji,'power',-6000); // 力量-6000,注意效果源
this.constEffectManager.compute(); // 强制计算,即使不是帧结束
});
});
},this).callback(this,function () {
this.packOutputs(function () {
cards.forEach(function (card,i) {
if (inArr(card,protectedSignis)) {
protectedFlags.push(true);
succs.push(true);
} else {
protectedFlags.push(false);
succs.push(card.moveTo(zones[i],args[i]));
}
},this);
},this);
this.frameEnd();
return {protectedFlags: protectedFlags, succs: succs};
});
};
// 只要有1只 SIGNI 被驱逐成功(包括代替)就返回 true.
Game.prototype.banishCardsAsyn = function (cards,force,arg) {
if (!arg) arg = {};
var attackingSigni = arg.attackingSigni || null;
var control = {
someBanished: false,
};
var source = this.getEffectSource();
cards = cards.filter(function (card) {
if (card.isEffectFiltered(source)) return false;
if (!card.canBeBanished()) return false;
return true;
},this);
if (!cards.length) return Callback.immediately(false);
this.frameStart();
return this.protectBanishAsyn(cards,this.turnPlayer,control).callback(this,function (cards) {
var zones = cards.map(function (card) {
// <绿叁游 水滑梯>
if (card.resonaBanishToTrash) return card.player.lrigTrashZone;
// 原枪
if (card.player.banishTrash) return card.player.trashZone;
// <原槍 エナジェ>
if (inArr(source,card.player._RanergeOriginalSpear)) return card.player.trashZone;
if (inArr(attackingSigni,card.player._RanergeOriginalSpear)) return card.player.trashZone;
return card.player.enerZone;
},this);
var opposingSignis = cards.map(function (card) {
return card.getOpposingSigni();
},this);
2017-05-07 17:56:15 +02:00
var accedCards = cards.map(function (card) {
return card.getAccedCards();
},this);
2016-10-23 07:56:45 +02:00
return this.moveCardsAdvancedAsyn(cards,zones,[],force).callback(this,function (arg) {
arg.protectedFlags.forEach(function (isProtected,i) {
if (isProtected) return;
if (!arg.succs[i]) return;
var signi = cards[i];
// <幻獣神 ウルティム>
var banishSource = attackingSigni || source;
var count;
if (banishSource) {
if (banishSource.hasClass('空獣') || banishSource.hasClass('地獣')) {
if (signi.player === banishSource.player.opponent) {
count = this.getData(banishSource.player,'_UltimPhantomBeastDeity') || 0;
this.setData(banishSource.player,'_UltimPhantomBeastDeity',++count);
}
}
}
var event = {
card: signi,
opposingSigni: opposingSignis[i],
2017-05-07 17:56:15 +02:00
accedCards: accedCards[i],
2016-10-23 07:56:45 +02:00
attackingSigni: attackingSigni,
source: banishSource
};
2016-10-25 16:52:27 +02:00
this.setData(signi.player,'flagSigniBanished',true);
2016-10-23 07:56:45 +02:00
signi.onBanish.trigger(event);
signi.player.onSigniBanished.trigger(event);
},this);
this.frameEnd();
return control.someBanished || !!arg.succs.length;
});
});
};
Game.prototype.protectBanishAsyn = function (cards,player,control) {
// 过滤不被驱逐的卡
cards = cards.filter(function (card) {
if (card.isEffectFiltered()) return false;
if (!card.canBeBanished()) return false;
return true;
},this);
// 获得玩家受保护的卡及其保护措施
var cardList = [];
var protectionTable = {};
cards.forEach(function (card) {
if (card.player !== player) return;
card.banishProtections.forEach(function (protection) {
if (!protection.condition.call(protection.source,card)) return;
if (protectionTable[card.gid]) {
protectionTable[card.gid].push(protection);
} else {
cardList.push(card);
protectionTable[card.gid] = [protection];
}
},this);
},this);
// 选择要保护的卡以及保护措施
return player.selectOptionalAsyn('PROTECT',cardList).callback(this,function (card) {
if (!card) {
// 回合玩家处理完毕,处理非回合玩家.
if (player === this.turnPlayer) {
return this.protectBanishAsyn(cards,player.opponent,control);
}
// 非回合玩家处理完毕,结束处理.
return cards;
}
card.beSelectedAsTarget();
var protections = protectionTable[card.gid];
return player.selectAsyn('CHOOSE_EFFECT',protections).callback(this,function (protection) {
protection.source.activate();
return protection.actionAsyn.call(protection.source,card).callback(this,function () {
control.someBanished = true;
this.constEffectManager.compute(); // 强制计算,即使不是帧结束
cards = cards.filter(function (c) {
if (c === card) return false; // 排除已被保护的卡
if (!inArr(c,c.player.signis)) return false; // 排除已不在场的卡
return true;
},this);
// 继续处理当前玩家.
return this.protectBanishAsyn(cards,player,control);
});
});
});
};
// Game.prototype.protectBanishAsyn = function () {
// // 代替驱逐
// return Callback.forEach(cards,function (card) {
// if (force) return;
// if (card.isEffectFiltered()) return;
// if (card.canNotBeBanished) return;
// if (card.power <= 0 ) return;
// // <堕落虚无 派蒙>
// if (card.trashCharmInsteadOfBanish && card.charm) {
// return card.player.selectOptionalAsyn('TRASH_CHARM',[card]).callback(this,function (c) {
// if (!c) return;
// someBanished = true;
// card.charm.trash();
// removeFromArr(card,cards);
// });
// }
// // <核心代号 S・W・T>
// if (card.discardSpellInsteadOfBanish) {
// var spells = card.player.hands.filter(function (card) {
// return card.type === 'SPELL';
// },this);
// if (!spells.length) return;
// return card.player.selectOptionalAsyn('PROTECT',[card]).callback(this,function (c) {
// if (!c) return;
// return card.player.selectAsyn('TRASH',spells).callback(this,function (spell) {
// if (!spell) return;
// someBanished = true;
// spell.trash();
// removeFromArr(card,cards);
// });
// });
// }
// // <コードハート M・P・P>
// if (card.protectingMpps.length) {
// // 获得保护该 SIGNI 的<M・P・P>
// var protectingMpps = card.protectingMpps.filter(function (mpp) {
// if (!inArr(mpp,card.player.signis)) return false;
// var spells = mpp.zone.cards.slice(1).filter(function (card) {
// return (card !== mpp.charm);
// },this);
// return (spells.length >= 2);
// },this);
// if (!protectingMpps.length) return;
// card.beSelectedAsTarget(); // 被驱逐的SIGNI闪烁
// return card.player.selectOptionalAsyn('PROTECT',protectingMpps).callback(this,function (mpp) {
// if (!mpp) return;
// var spells = mpp.zone.cards.slice(1).filter(function (card) {
// return (card !== mpp.charm);
// },this);
// return card.player.selectSomeAsyn('TRASH',spells,2,2).callback(this,function (spells) {
// mpp.activate();
// this.trashCards(spells);
// someBanished = true;
// removeFromArr(card,cards);
// });
// });
// }
// },this)
// };
// Game.prototype.banishCards = function (cards) {
// if (!cards.length) return;
// cards = cards.slice();
// this.packOutputs(function () {
// this.frameStart();
// cards.forEach(function (card) {
// card.beBanished();
// },this);
// this.frameEnd();
// });
// };
// Game.prototype.doBanishCards = function (cards) {
// if (!cards.length) return;
// cards = cards.slice();
// this.packOutputs(function () {
// this.frameStart();
// cards.forEach(function (card) {
// card.doBanish();
// },this);
// this.frameEnd();
// });
// };
// Game.prototype.banishCardsAsyn = function (cards) {
// if (!cards.length) return Callback.immediately();
// cards = cards.slice();
// return this.packOutputs(function () {
// this.frameStart();
// return Callback.forEach(cards,function (card) {
// return card.banishAsyn();
// },this).callback(this,function () {
// this.frameEnd();
// });
// });
// };
Game.prototype.trashCardsAsyn = function (cards,arg) {
if (!cards.length) return Callback.immediately();
cards = cards.slice();
var zones = cards.map(function (card) {
if (inArr(card.type,['LRIG','ARTS'])) return card.player.lrigTrashZone;
return card.player.trashZone;
},this);
var args = cards.map(function (card) {
return arg || {};
},this);
return this.moveCardsAdvancedAsyn(cards,zones,[],args);
};
Game.prototype.bounceCardsAsyn = function (cards) {
if (!cards.length) return Callback.immediately();
cards = cards.slice();
var zones = cards.map(function (card) {
return card.player.handZone;
},this);
return this.moveCardsAdvancedAsyn(cards,zones,[]);
};
Game.prototype.bounceCardsToDeckAsyn = function (cards) {
if (!cards.length) return Callback.immediately();
cards = cards.slice();
var zones = cards.map(function (card) {
if (inArr(this.type,['LRIG','ARTS'])) return card.player.lrigDeck;
return card.player.mainDeck;
},this);
return this.moveCardsAdvancedAsyn(cards,zones,[]);
};
Game.prototype.trashCards = function (cards,arg) {
if (!cards.length) return;
cards = cards.slice();
this.packOutputs(function () {
this.frameStart();
cards = cards.filter(function (card) {
return card.trash(arg);
},this);
this.frameEnd();
});
return cards;
};
Game.prototype.excludeCards = function (cards) {
if (!cards.length) return;
cards = cards.slice();
this.packOutputs(function () {
this.frameStart();
cards = cards.filter(function (card) {
card.exclude();
},this);
this.frameEnd();
});
return cards;
};
Game.prototype.upCards = function (cards) {
if (!cards.length) return;
this.packOutputs(function () {
this.frameStart();
cards = cards.filter(function (card) {
return card.up();
},this);
this.frameEnd();
});
return cards;
};
2016-12-01 15:07:33 +01:00
Game.prototype.upCardsAsyn = function (cards) {
if (!cards.length) return;
var upCards = [];
this.frameStart();
return Callback.forEach(cards,function (card) {
return card.upAsyn().callback(this,function (succ) {
if (succ) upCards.push(card);
});
}).callback(this,function () {
this.frameEnd();
return upCards;
});
};
2016-10-23 07:56:45 +02:00
Game.prototype.downCards = function (cards) {
if (!cards.length) return;
this.packOutputs(function () {
this.frameStart();
cards = cards.filter(function (card) {
card.down();
},this);
this.frameEnd();
});
return cards;
};
// Game.prototype.informPower = function () {
// var cards = concat(this.turnPlayer.signis,this.turnPlayer.opponent.signis);
// var powers = cards.map(function (card) {
// return card.power;
// });
// this.output({
// type: 'POWER',
// content: {
// cards: cards,
// powers: powers
// }
// });
// };
Game.prototype.outputCardStates = function () {
var cards = concat(this.turnPlayer.signis,this.turnPlayer.opponent.signis);
var signiInfos = cards.map(function (card) {
return {
card: card,
power: card.power,
states: card.getStates()
}
},this);
cards = [this.turnPlayer.lrig,this.turnPlayer.opponent.lrig];
var lrigInfos = cards.map(function (card) {
return {
card: card,
states: card.getStates()
}
},this);
var zones = concat(this.turnPlayer.signiZones,this.turnPlayer.opponent.signiZones);
var zoneInfos = zones.map(function (zone) {
return {
zone: zone,
states: zone.getStates()
}
},this);
this.output({
type: 'CARD_STATES',
content: {
signiInfos: signiInfos,
lrigInfos: lrigInfos,
zoneInfos: zoneInfos
}
});
};
Game.prototype.addConstEffect = function (cfg,dontCompute) {
var constEffect = new ConstEffect(this.constEffectManager,cfg);
if (!dontCompute) {
this.handleFrameEnd();
}
return constEffect;
};
Game.prototype.newEffect = function (eff) {
return new Effect(this.effectManager,eff);
};
Game.prototype.frame = function (thisp,func) {
if (arguments.length !== 2) {
debugger;
}
this.frameStart();
func.call(thisp);
this.frameEnd();
};
Game.prototype.frameStart = function () {
this._frameCount++;
};
Game.prototype.frameEnd = function () {
if (this._frameCount <= 0) {
debugger;
console.warn('game._frameCount <= 0');
this._frameCount = 0;
return;
}
this._frameCount--;
this.handleFrameEnd();
};
Game.prototype.handleFrameEnd = function () {
if (this._frameCount) return;
this._framedBeforeBlock = true;
this.constEffectManager.compute();
this.triggeringEffects.forEach(function (effect,idx) {
effect.trigger(this.triggeringEvents[idx]);
},this);
this.triggeringEffects.length = 0;
this.triggeringEvents.length = 0;
};
Game.prototype.pushTriggeringEffect = function (effect,event) {
this.triggeringEffects.push(effect);
this.triggeringEvents.push(event);
};
Game.prototype.pushEffectSource = function (source) {
this._sources.push(source || null);
};
Game.prototype.popEffectSource = function (source) {
return this._sources.pop();
};
Game.prototype.getEffectSource = function () {
if (!this._sources.length) return null;
return this._sources[this._sources.length-1];
};
Game.prototype.blockAsyn = function (source,thisp,func) {
if (arguments.length !== 3) {
if (arguments.length === 2) {
source = null;
thisp = arguments[0];
func = arguments[1];
} else {
debugger;
console.warn('game.blockAsyn() 参数个数不正确');
}
}
this.blockStart(source);
return Callback.immediately().callback(thisp,func).callback(this,function (rtn) {
return this.blockEndAsyn().callback(this,function () {
return rtn;
});
});
};
// Game.prototype.block = function (source,thisp,func) {
// this.pushEffectSource(source);
// func.call(thisp);
// this.popEffectSource();
// };
Game.prototype.blockStart = function (source) {
this.pushEffectSource(source);
};
Game.prototype.blockEndAsyn = function () {
if (this._sources.length <= 0) {
debugger;
console.warn('game._sources.length <= 0');
return Callback.immediately();
}
this.popEffectSource();
return this.handleBlockEndAsyn();
};
Game.prototype.handleBlockEndAsyn = function () {
if (this._sources.length) return Callback.immediately();
this.frameStart();
return this.turnPlayer.resetSignisAsyn().callback(this,function () {
return this.turnPlayer.opponent.resetSignisAsyn();
}).callback(this,function () {
this.frameEnd();
return this.banishNonPositiveAsyn();
}).callback(this,function () {
// 废弃【魅饰】和SIGNI下方的卡
this.trashingCards.forEach(function (card) {
2017-02-26 12:36:54 +01:00
card.acceingCard = null;
},this);
this.trashCards(this.trashingCharms,{ isCharm: true });
this.trashCards(this.trashingCards);
this.trashingCharms.length = 0;
this.trashingCards.length = 0;
2016-10-23 07:56:45 +02:00
return this.rebuildAsyn();
}).callback(this,function () {
return this.effectManager.handleEffectsAsyn();
});
// return this.banishNonPositiveAsyn().callback(this,function () {
// return this.rebuildAsyn().callback(this,function () {
// return this.effectManager.handleEffectsAsyn();
// });
// });
};
Game.prototype.banishNonPositiveAsyn = function () {
if (!this._framedBeforeBlock) return Callback.immediately();
this._framedBeforeBlock = false;
var signis = concat(this.turnPlayer.signis,this.turnPlayer.opponent.signis).filter(function (signi) {
return (signi.power <= 0);
},this);
if (!signis.length) Callback.immediately();
return Callback.immediately().callback(this,function () {
this.pushEffectSource(null);
if (this.trashWhenPowerBelowZero) {
return this.trashCards(signis);
}
return this.banishCardsAsyn(signis,true);
}).callback(this,function () {
this.popEffectSource();
return this.banishNonPositiveAsyn();
});
};
Game.prototype.rebuildAsyn = function () {
var players = [this.turnPlayer,this.turnPlayer.opponent].filter(function (player) {
return !player.mainDeck.cards.length && player.trashZone.cards.length;
},this);
if (!players.length) return Callback.immediately();
return this.blockAsyn(this,function () {
// console.log('game.rebuildAsyn()');
// 将废弃区的卡片放到牌组,洗切
this.frameStart();
return Callback.forEach(players,function (player) {
var cards = player.trashZone.cards;
return player.showCardsAsyn(cards,'CONFIRM_REFRESH_SELF').callback(this,function () {
return player.opponent.showCardsAsyn(cards,'CONFIRM_REFRESH_OPPONENT');
}).callback(this,function () {
player.rebuildCount++;
this.moveCards(player.trashZone.cards,player.mainDeck);
player.shuffle();
player.onRebuild.trigger({
rebuildCount: player.rebuildCount
});
});
},this).callback(this,function () {
this.frameEnd();
// 废弃一张生命护甲
var cards = [];
players.forEach(function (player) {
cards = cards.concat(player.lifeClothZone.getTopCards(1));
},this);
this.trashCards(cards);
});
// this.frame(this,function () {
// players.forEach(function (player) {
// player.rebuildCount++;
// this.moveCards(player.trashZone.cards,player.mainDeck);
// player.shuffle();
// player.onRebuild.trigger({
// rebuildCount: player.rebuildCount
// });
// },this);
// });
// // 废弃一张生命护甲
// var cards = [];
// players.forEach(function (player) {
// cards = cards.concat(player.lifeClothZone.getTopCards(1));
// },this);
// this.trashCards(cards);
});
};
Game.prototype.setAdd = function (source,obj,prop,value,isSet,arg) {
if (!arg) arg = {};
if (!arg.forced) {
if (obj.isEffectFiltered && obj.isEffectFiltered(source)) return;
2016-11-17 15:13:19 +01:00
var card = null;
if (obj.player && inArr(prop,Card.abilityProps)) {
card = obj;
} else if (isObj(value) && (value.constructor === Effect)) {
card = value.source;
if (card.isEffectFiltered(source)) return;
2016-10-23 07:56:45 +02:00
}
2016-11-17 15:13:19 +01:00
if (card) {
if (card.canNotGainAbility || card.player.canNotGainAbility) return;
if (card.canNotGainAbilityBySelfPlayer) {
if (source.player === card.player) {
return;
}
}
2016-10-23 07:56:45 +02:00
}
}
var destroyTimming = [this.phase.onTurnEnd];
if (obj.type === 'SIGNI') {
if (inArr(obj,obj.player.signis)) {
destroyTimming.push(obj.onLeaveField);
}
}
this.frameStart();
this.addConstEffect({
source: source,
fixed: true,
destroyTimming: destroyTimming,
action: function (set,add) {
var target = obj;
if (obj.type === 'LRIG') {
target = obj.player.lrig;
}
if (isSet) {
set(target,prop,value,arg);
} else {
add(target,prop,value,arg);
}
}
});
if (obj.triggerOnAffect) {
obj.triggerOnAffect(source);
}
this.frameEnd();
};
Game.prototype.tillTurnEndSet = function (source,obj,prop,value,arg) {
this.setAdd(source,obj,prop,value,true,arg);
};
Game.prototype.tillTurnEndAdd = function (source,obj,prop,value,arg) {
this.setAdd(source,obj,prop,value,false,arg);
};
Game.prototype.getData = function (obj,key) {
var hash = obj.gid + key;
return this.dataObj[hash];
};
Game.prototype.setData = function (obj,key,value) {
var hash = obj.gid + key;
this.dataObj[hash] = value;
};
Game.prototype.clearData = function () {
this.dataObj = {};
};
Game.prototype.getOriginalValue = function (obj,prop) {
return this.constEffectManager.getOriginalValue(obj,prop);
};
Game.prototype.gameover = function (arg) {
if (!arg) arg = {};
var win,surrender;
if (arg.surrender === 'host') {
surrender = true;
win = false;
} else if (arg.surrender === 'guest') {
surrender = true;
win = true;
} else {
surrender = false;
win = (this.winner === this.hostPlayer);
}
if (!this.hostPlayer.lrig || !this.guestPlayer.lrig) {
this.onGameover(null);
return;
}
var replayObj = {
win: win,
surrender: surrender,
selfLrig: this.hostPlayer.lrig.cid,
opponentLrig: this.guestPlayer.lrig.cid,
messagePacks: this.hostPlayer.messagePacks
};
this.onGameover(replayObj);
};
Game.prototype.getLiveMessagePacks = function () {
return this.hostPlayer.messagePacks;
};
global.Game = Game;