mirror of
https://github.com/Shu-Ying/noname-shuying.git
synced 2026-10-03 10:30:14 +08:00
88 lines
3.5 KiB
JavaScript
88 lines
3.5 KiB
JavaScript
// Track only the turn created by this battle's cooperative loop.
|
|
const battleTurns = new WeakMap();
|
|
const turnStages = new Set(["phase", "phaseZhunbei", "phaseJudge", "phaseDraw", "phaseUse", "phaseDiscard", "phaseJieshu"]);
|
|
|
|
export function stopBattleTurn(session, eventManager) {
|
|
const turn = battleTurns.get(session);
|
|
if (!turn) return;
|
|
const belongsToTurn = event => {
|
|
const seen = new Set();
|
|
while (event && !seen.has(event)) {
|
|
if (event === turn) return true;
|
|
seen.add(event);
|
|
event = event.parent;
|
|
}
|
|
return false;
|
|
};
|
|
// Finish phase controllers, not the card/damage/death events currently resolving.
|
|
// Those events must unwind before the session can safely dispose players.
|
|
for (const event of eventManager.eventStack.slice().reverse()) {
|
|
if (turnStages.has(event.name) && belongsToTurn(event)) event.finish();
|
|
}
|
|
turn.finish();
|
|
}
|
|
|
|
// Candidate derived from local engine phaseLoop; no global replacement.
|
|
export async function runPhaseLoop(event, player, session, { game, lib, _status, get, beforeTurn = async () => {} }) {
|
|
let num = 1;
|
|
let current = player;
|
|
while (session.active && !event.finished && current.getSeatNum() === 0) {
|
|
current.setSeatNum(num);
|
|
current = current.next;
|
|
num++;
|
|
}
|
|
while (session.active && !event.finished) {
|
|
if (game.players.includes(event.player)) {
|
|
await beforeTurn(event.player);
|
|
if (!session.active || event.finished) return;
|
|
lib.onphase.forEach((i) => i());
|
|
if (!session.active || event.finished) return;
|
|
const phase = event.player.phase();
|
|
battleTurns.set(session, phase);
|
|
try {
|
|
event.next.remove(phase);
|
|
let isRoundEnd = false;
|
|
if (lib.onround.every((i) => i(phase, event.player))) {
|
|
isRoundEnd = _status.roundSkipped;
|
|
if (_status.isRoundFilter) {
|
|
isRoundEnd = _status.isRoundFilter(phase, event.player);
|
|
} else if (_status.seatNumSettled) {
|
|
const seatNum = event.player.getSeatNum();
|
|
if (seatNum != 0) {
|
|
if (get.itemtype(_status.lastPhasedPlayer) != "player" || seatNum < _status.lastPhasedPlayer.getSeatNum()) {
|
|
isRoundEnd = true;
|
|
}
|
|
}
|
|
} else if (event.player == _status.roundStart) {
|
|
isRoundEnd = true;
|
|
}
|
|
if (isRoundEnd && _status.globalHistory.some((i) => i.isRound)) {
|
|
game.log();
|
|
await event.trigger("roundEnd");
|
|
}
|
|
}
|
|
if (!session.active || event.finished) { phase.finish(); return; }
|
|
event.next.push(phase);
|
|
await phase;
|
|
} finally {
|
|
if (battleTurns.get(session) === phase) battleTurns.delete(session);
|
|
}
|
|
}
|
|
if (!session.active || event.finished) return;
|
|
await event.trigger("phaseOver");
|
|
if (!session.active || event.finished) return;
|
|
const findNext = (current2) => {
|
|
const players = game.players.slice(0).concat(game.dead).sort((a, b) => parseInt(a.dataset.position) - parseInt(b.dataset.position));
|
|
const position = parseInt(current2.dataset.position);
|
|
for (const player2 of players) {
|
|
if (parseInt(player2.dataset.position) > position) {
|
|
return player2;
|
|
}
|
|
}
|
|
return players[0];
|
|
};
|
|
event.player = findNext(event.player);
|
|
if (!event.player) return;
|
|
}
|
|
}
|