179 lines
4.7 KiB
TypeScript
179 lines
4.7 KiB
TypeScript
const m = require('mithril');
|
|
const makeItems = require('./item').ctrl;
|
|
const itemView = require('./item').view;
|
|
const makeScenario = require('./scenario');
|
|
const makeChess = require('./chess');
|
|
const ground = require('./ground');
|
|
const scoring = require('./score');
|
|
const sound = require('./sound');
|
|
const promotion = require('./promotion');
|
|
const timeouts = require('./timeouts');
|
|
|
|
module.exports = function (blueprint, opts) {
|
|
const items = makeItems({
|
|
apples: blueprint.apples,
|
|
});
|
|
|
|
const vm = {
|
|
lastStep: false,
|
|
completed: false,
|
|
willComplete: false,
|
|
failed: false,
|
|
score: 0,
|
|
nbMoves: 0,
|
|
};
|
|
|
|
const complete = function () {
|
|
vm.willComplete = true;
|
|
vm.score += scoring.getLevelBonus(blueprint, vm.nbMoves);
|
|
opts.onCompleteImmediate();
|
|
timeouts.setTimeout(
|
|
function () {
|
|
vm.lastStep = false;
|
|
vm.completed = true;
|
|
sound.levelEnd();
|
|
ground.stop();
|
|
m.redraw();
|
|
if (!blueprint.nextButton) timeouts.setTimeout(opts.onComplete, 1200);
|
|
},
|
|
ground.data().stats.dragged ? 1 : 250
|
|
);
|
|
};
|
|
|
|
// cheat
|
|
// Mousetrap.bind(['shift+enter'], complete);
|
|
|
|
const assertData = function () {
|
|
return {
|
|
scenario: scenario,
|
|
chess: chess,
|
|
vm: vm,
|
|
};
|
|
};
|
|
|
|
const detectFailure = function () {
|
|
const failed = blueprint.failure && blueprint.failure(assertData());
|
|
if (failed) sound.failure();
|
|
return failed;
|
|
};
|
|
|
|
const detectSuccess = function () {
|
|
if (blueprint.success) return blueprint.success(assertData());
|
|
else return !items.hasItem('apple');
|
|
};
|
|
|
|
const detectCapture = function () {
|
|
if (!blueprint.detectCapture) return false;
|
|
const fun = blueprint.detectCapture === 'unprotected' ? 'findUnprotectedCapture' : 'findCapture';
|
|
const move = chess[fun]();
|
|
if (!move) return;
|
|
vm.failed = true;
|
|
ground.stop();
|
|
ground.showCapture(move);
|
|
sound.failure();
|
|
return true;
|
|
};
|
|
|
|
const sendMove = function (orig, dest, prom) {
|
|
vm.nbMoves++;
|
|
const move = chess.move(orig, dest, prom);
|
|
if (move) ground.fen(chess.fen(), blueprint.color, {});
|
|
else {
|
|
// moving into check
|
|
vm.failed = true;
|
|
ground.showCheckmate(chess);
|
|
sound.failure();
|
|
return m.redraw();
|
|
}
|
|
let took = false,
|
|
inScenario,
|
|
captured = false;
|
|
items.withItem(move.to, function (item) {
|
|
if (item === 'apple') {
|
|
vm.score += scoring.apple;
|
|
items.remove(move.to);
|
|
took = true;
|
|
}
|
|
});
|
|
if (!took && move.captured && blueprint.pointsForCapture) {
|
|
if (blueprint.showPieceValues) vm.score += scoring.pieceValue(move.captured);
|
|
else vm.score += scoring.capture;
|
|
took = true;
|
|
}
|
|
ground.check(chess);
|
|
if (scenario.player(move.from + move.to + (move.promotion || ''))) {
|
|
vm.score += scoring.scenario;
|
|
inScenario = true;
|
|
} else {
|
|
captured = detectCapture();
|
|
vm.failed = vm.failed || captured || detectFailure();
|
|
}
|
|
if (!vm.failed && detectSuccess()) complete();
|
|
if (vm.willComplete) return;
|
|
if (took) sound.take();
|
|
else if (inScenario) sound.take();
|
|
else sound.move();
|
|
if (vm.failed) {
|
|
if (blueprint.showFailureFollowUp && !captured)
|
|
timeouts.setTimeout(function () {
|
|
const rm = chess.playRandomMove();
|
|
ground.fen(chess.fen(), blueprint.color, {}, [rm.orig, rm.dest]);
|
|
}, 600);
|
|
} else {
|
|
ground.select(dest);
|
|
if (!inScenario) {
|
|
chess.color(blueprint.color);
|
|
ground.color(blueprint.color, makeChessDests());
|
|
}
|
|
}
|
|
m.redraw();
|
|
};
|
|
|
|
var makeChessDests = function () {
|
|
return chess.dests({
|
|
illegal: blueprint.offerIllegalMove,
|
|
});
|
|
};
|
|
|
|
const onMove = function (orig, dest) {
|
|
const piece = ground.get(dest);
|
|
if (!piece || piece.color !== blueprint.color) return;
|
|
if (!promotion.start(orig, dest, sendMove)) sendMove(orig, dest);
|
|
};
|
|
|
|
var chess = makeChess(blueprint.fen, blueprint.emptyApples ? [] : items.appleKeys());
|
|
|
|
var scenario = makeScenario(blueprint.scenario, {
|
|
chess: chess,
|
|
makeChessDests: makeChessDests,
|
|
});
|
|
|
|
promotion.reset();
|
|
|
|
ground.set({
|
|
chess: chess,
|
|
offerIllegalMove: blueprint.offerIllegalMove,
|
|
autoCastle: blueprint.autoCastle,
|
|
orientation: blueprint.color,
|
|
onMove: onMove,
|
|
items: {
|
|
render: function (pos, key) {
|
|
return items.withItem(key, itemView);
|
|
},
|
|
},
|
|
shapes: blueprint.shapes,
|
|
});
|
|
|
|
return {
|
|
blueprint: blueprint,
|
|
items: items,
|
|
vm: vm,
|
|
scenario: scenario,
|
|
start: function () {
|
|
sound.levelStart();
|
|
if (chess.color() !== blueprint.color) timeouts.setTimeout(scenario.opponent, 1000);
|
|
},
|
|
onComplete: opts.onComplete,
|
|
};
|
|
};
|