webxoss-core/Game.js
2016-12-10 14:30:37 +08:00

1124 lines
No EOL
31 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'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 = [];
// 注册
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) {
if (info.sideA) {
info = CardInfo[info.sideA]
}
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;
}
// 禁止 台风蛇
if (infos.some(function (info) {
return info.cid === 957; // 台風一過
}) && infos.some(function (info) {
return (info.cid === 1652); // コードアンシエンツ ヘルボロス
})) {
return false;
}
// 限制
var limitMap = {
37: 2, // <忘得ぬ幻想 ヴァルキリー>
34: 2, // <修復>
178: 2, // <先駆の大天使 アークゲイン>
534: 1, // <ロック・ユー>
// 689: 1, // <>
474: 0, // <ノー・ゲイン>
23: 0, // <大器晩成>
689: 0, // <>
1030: 0, // <四面楚火>
1457: 0, // <サーバント Z>
};
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,
lrigDeckCardInfos: player.lrigDeck.cards.map(function (card) {
return {
pid: card.pid,
isSide: !!card.sideA
}
},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,
lrigDeckCardInfos: opponent.lrigDeck.cards.map(function (card) {
return {
pid: 0,
isSide: !!card.sideA
}
},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);
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],
attackingSigni: attackingSigni,
source: banishSource
};
this.setData(signi.player,'flagSigniBanished',true);
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;
};
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;
});
};
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.trashCards(this.trashingCharms,{ isCharm: true });
this.trashCards(this.trashingCards);
this.trashingCharms.length = 0;
this.trashingCards.length = 0;
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;
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;
}
if (card) {
if (card.canNotGainAbility || card.player.canNotGainAbility) return;
if (card.canNotGainAbilityBySelfPlayer) {
if (source.player === card.player) {
return;
}
}
}
}
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;