lila/ui/round/src/promotion.ts

126 lines
3.8 KiB
TypeScript

import { h } from 'snabbdom'
import * as ground from './ground';
import * as cg from 'chessground/types';
import { DrawShape } from 'chessground/draw';
import xhr = require('./xhr');
import { key2pos } from 'chessground/util';
import { bind } from './util';
import RoundController from './ctrl';
interface Promoting {
move: [cg.Key, cg.Key];
pre: boolean;
meta: cg.MoveMetadata
}
let promoting: Promoting | undefined;
let prePromotionRole: cg.Role | undefined;
function sendPromotion(ctrl: RoundController, orig: cg.Key, dest: cg.Key, role: cg.Role, meta: cg.MoveMetadata): boolean {
ground.promote(ctrl.chessground, dest, role);
ctrl.sendMove(orig, dest, role, meta);
return true;
}
export function start(ctrl: RoundController, orig: cg.Key, dest: cg.Key, meta: cg.MoveMetadata = {} as cg.MoveMetadata): boolean {
const d = ctrl.data,
piece = ctrl.chessground.state.pieces[dest],
premovePiece = ctrl.chessground.state.pieces[orig];
if (((piece && piece.role === 'pawn') || (premovePiece && premovePiece.role === 'pawn')) && (
(dest[1] === '8' && d.player.color === 'white') ||
(dest[1] === '1' && d.player.color === 'black'))) {
if (prePromotionRole && meta && meta.premove) return sendPromotion(ctrl, orig, dest, prePromotionRole, meta);
if (!meta.ctrlKey && !promoting && (d.pref.autoQueen === 3 || (d.pref.autoQueen === 2 && premovePiece))) {
if (premovePiece) setPrePromotion(ctrl, dest, 'queen');
else sendPromotion(ctrl, orig, dest, 'queen', meta);
return true;
}
promoting = {
move: [orig, dest],
pre: !!premovePiece,
meta
};
ctrl.redraw();
return true;
}
return false;
}
function setPrePromotion(ctrl: RoundController, dest: cg.Key, role: cg.Role): void {
prePromotionRole = role;
ctrl.chessground.setAutoShapes([{
orig: dest,
piece: {
color: ctrl.data.player.color,
role,
opacity: 0.8
},
brush: ''
} as DrawShape]);
}
export function cancelPrePromotion(ctrl: RoundController) {
if (prePromotionRole) {
ctrl.chessground.setAutoShapes([]);
prePromotionRole = undefined;
ctrl.redraw();
}
}
function finish(ctrl: RoundController, role: cg.Role) {
if (promoting) {
const info = promoting;
promoting = undefined;
if (info.pre) setPrePromotion(ctrl, info.move[1], role);
else sendPromotion(ctrl, info.move[0], info.move[1], role, info.meta);
}
}
export function cancel(ctrl: RoundController) {
cancelPrePromotion(ctrl);
ctrl.chessground.cancelPremove();
if (promoting) xhr.reload(ctrl).then(ctrl.reload);
promoting = undefined;
}
function renderPromotion(ctrl: RoundController, dest: cg.Key, roles: cg.Role[], color: Color, orientation: Color) {
var left = (8 - key2pos(dest)[0]) * 12.5;
if (orientation === 'white') left = 87.5 - left;
var vertical = color === orientation ? 'top' : 'bottom';
return h('div#promotion_choice.' + vertical, {
hook: {
insert: vnode => {
const el = vnode.elm as HTMLElement;
el.addEventListener('click', () => cancel(ctrl));
el.addEventListener('contextmenu', e => {
e.preventDefault();
return false;
});
}
}
}, roles.map((serverRole, i) => {
var top = (color === orientation ? i : 7 - i) * 12.5;
return h('square', {
attrs: {style: 'top: ' + top + '%;left: ' + left + '%'},
hook: bind('click', e => {
e.stopPropagation();
finish(ctrl, serverRole);
})
}, [
h('piece.' + serverRole + '.' + color)
]);
}));
};
const roles: cg.Role[] = ['queen', 'knight', 'rook', 'bishop'];
export function view(ctrl: RoundController) {
if (!promoting) return;
return renderPromotion(ctrl, promoting.move[1],
ctrl.data.game.variant.key === 'antichess' ? roles.concat('king') : roles,
ctrl.data.player.color,
ctrl.chessground.state.orientation);
};