+ // Apply mushroom, bomb or banana effect (hidden to the player).
+ // Determine egg effect, too, and apply its first part if possible.
+ getBasicMove_aux(psq1, sq2, tr, initMove) {
+ const [x1, y1] = [psq1.x, psq1.y];
+ const color1 = this.turn;
+ const piece1 = (!!tr ? tr.p : (psq1.p || this.getPiece(x1, y1)));
+ const oppCol = V.GetOppCol(color1);
+ if (!sq2) {
+ let move = {
+ appear: [],
+ vanish: []
+ };
+ // banana or bomb defines next square, or the move ends there
+ move.appear = [
+ new PiPo({
+ x: x1,
+ y: y1,
+ c: color1,
+ p: piece1
+ })
+ ];
+ if (this.board[x1][y1] != V.EMPTY) {
+ const initP1 = this.getPiece(x1, y1);
+ move.vanish = [
+ new PiPo({
+ x: x1,
+ y: y1,
+ c: this.getColor(x1, y1),
+ p: initP1
+ })
+ ];
+ if ([V.BANANA, V.BOMB].includes(initP1)) {
+ const steps = V.steps[initP1 == V.BANANA ? V.ROOK : V.BISHOP];
+ move.next = this.getRandomSquare([x1, y1], steps);
+ }
+ }
+ move.end = { x: x1, y: y1 };
+ return move;
+ }
+ const [x2, y2] = [sq2[0], sq2[1]];
+ // The move starts normally, on board:
+ let move = super.getBasicMove([x1, y1], [x2, y2], tr);
+ if (!!tr) move.promoteInto = tr.c + tr.p; //in case of (chomped...)
+ const L = this.effects.length;
+ if (
+ [V.PAWN, V.KNIGHT].includes(piece1) &&
+ !!initMove &&
+ (this.subTurn == 1 || this.effects[L-1] == "daisy")
+ ) {
+ switch (piece1) {
+ case V.PAWN: {
+ const twoSquaresMove = (Math.abs(x2 - x1) == 2);
+ const mushroomX = x1 + (twoSquaresMove ? (x2 - x1) / 2 : 0);
+ move.appear.push(
+ new PiPo({
+ x: mushroomX,
+ y: y1,
+ c: 'a',
+ p: V.MUSHROOM
+ })
+ );
+ if (this.getColor(mushroomX, y1) == 'a') {
+ move.vanish.push(
+ new PiPo({
+ x: mushroomX,
+ y: y1,
+ c: 'a',
+ p: this.getPiece(mushroomX, y1)
+ })
+ );
+ }
+ break;
+ }
+ case V.KNIGHT: {
+ const deltaX = Math.abs(x2 - x1);
+ const deltaY = Math.abs(y2 - y1);
+ let eggSquare = [
+ x1 + (deltaX == 2 ? (x2 - x1) / 2 : 0),
+ y1 + (deltaY == 2 ? (y2 - y1) / 2 : 0)
+ ];
+ if (
+ this.board[eggSquare[0]][eggSquare[1]] != V.EMPTY &&
+ this.getColor(eggSquare[0], eggSquare[1]) != 'a'
+ ) {
+ eggSquare[0] = x1;
+ eggSquare[1] = y1;
+ }
+ move.appear.push(
+ new PiPo({
+ x: eggSquare[0],
+ y: eggSquare[1],
+ c: 'a',
+ p: V.EGG
+ })
+ );
+ if (this.getColor(eggSquare[0], eggSquare[1]) == 'a') {
+ move.vanish.push(
+ new PiPo({
+ x: eggSquare[0],
+ y: eggSquare[1],
+ c: 'a',
+ p: this.getPiece(eggSquare[0], eggSquare[1])
+ })
+ );
+ }
+ break;
+ }
+ }
+ }
+ // For (wa)luigi effect:
+ const changePieceColor = (color) => {
+ let pieces = [];
+ const oppLastRank = (color == 'w' ? 7 : 0);
+ for (let i=0; i<8; i++) {
+ for (let j=0; j<8; j++) {
+ if (
+ (i != move.vanish[0].x || j != move.vanish[0].y) &&
+ this.board[i][j] != V.EMPTY &&
+ this.getColor(i, j) == color
+ ) {
+ const piece = this.getPiece(i, j);
+ if (piece != V.KING && (piece != V.PAWN || i != oppLastRank))
+ pieces.push({ x: i, y: j, p: piece });
+ }
+ }
+ }
+ // Special case of the current piece (still at its initial position)
+ if (color == color1)
+ pieces.push({ x: move.appear[0].x, y: move.appear[0].y, p: piece1 });
+ const cp = pieces[randInt(pieces.length)];
+ if (move.appear[0].x != cp.x || move.appear[0].y != cp.y) {
+ move.vanish.push(
+ new PiPo({
+ x: cp.x,
+ y: cp.y,
+ c: color,
+ p: cp.p
+ })
+ );
+ }
+ else move.appear.shift();
+ move.appear.push(
+ new PiPo({
+ x: cp.x,
+ y: cp.y,
+ c: V.GetOppCol(color),
+ p: cp.p
+ })
+ );
+ };
+ const applyEggEffect = () => {
+ if (this.subTurn == 2)
+ // No egg effects at subTurn 2
+ return;
+ // 1) Determine the effect (some may be impossible)
+ let effects = ["kingboo", "koopa", "chomp", "bowser", "daisy"];
+ if (Object.values(this.captured[color1]).some(c => c >= 1))
+ effects.push("toadette");
+ const lastRank = { 'w': 0, 'b': 7 };
+ if (
+ this.board.some((b,i) =>
+ b.some(cell => {
+ return (
+ cell[0] == oppCol &&
+ cell[1] != V.KING &&
+ (cell[1] != V.PAWN || i != lastRank[color1])
+ );
+ })
+ )
+ ) {
+ effects.push("luigi");
+ }
+ if (
+ (
+ piece1 != V.KING &&
+ (piece1 != V.PAWN || move.appear[0].x != lastRank[oppCol])
+ ) ||
+ this.board.some((b,i) =>
+ b.some(cell => {
+ return (
+ cell[0] == color1 &&
+ cell[1] != V.KING &&
+ (cell[1] != V.PAWN || i != lastRank[oppCol])
+ );
+ })
+ )
+ ) {
+ effects.push("waluigi");
+ }
+ const effect = effects[randInt(effects.length)];
+ move.end.effect = effect;
+ // 2) Apply it if possible
+ if (!(["kingboo", "toadette", "daisy"].includes(effect))) {
+ switch (effect) {
+ case "koopa":
+ move.appear = [];
+ // Maybe egg effect was applied after others,
+ // so just shift vanish array:
+ move.vanish.shift();
+ break;
+ case "chomp":
+ move.appear = [];
+ break;
+ case "bowser":
+ move.appear[0].p = V.IMMOBILIZE_CODE[piece1];
+ break;
+ case "luigi":
+ changePieceColor(oppCol);
+ break;
+ case "waluigi":
+ changePieceColor(color1);
+ break;
+ }
+ }
+ };
+ const applyMushroomEffect = () => {
+ if ([V.PAWN, V.KING, V.KNIGHT].includes(piece1)) {
+ // Just make another similar step, if possible (non-capturing)
+ const [i, j] = [
+ move.appear[0].x + (x2 - x1),
+ move.appear[0].y + (y2 - y1)
+ ];
+ if (
+ V.OnBoard(i, j) &&
+ (this.board[i][j] == V.EMPTY || this.getColor(i, j) == 'a')
+ ) {
+ move.appear[0].x = i;
+ move.appear[0].y = j;
+ if (this.board[i][j] != V.EMPTY) {
+ const object = this.getPiece(i, j);
+ move.vanish.push(
+ new PiPo({
+ x: i,
+ y: j,
+ c: 'a',
+ p: object
+ })
+ );
+ switch (object) {
+ case V.BANANA:
+ case V.BOMB:
+ const steps = V.steps[object == V.BANANA ? V.ROOK : V.BISHOP];
+ move.next = this.getRandomSquare([i, j], steps);
+ break;
+ case V.EGG:
+ applyEggEffect();
+ break;
+ case V.MUSHROOM:
+ applyMushroomEffect();
+ break;
+ }
+ }
+ }
+ }
+ else {
+ // Queen, bishop or rook:
+ const step = [
+ (x2 - x1) / Math.abs(x2 - x1) || 0,
+ (y2 - y1) / Math.abs(y2 - y1) || 0
+ ];
+ const next = [move.appear[0].x + step[0], move.appear[0].y + step[1]];
+ if (
+ V.OnBoard(next[0], next[1]) &&
+ this.board[next[0]][next[1]] != V.EMPTY &&
+ this.getColor(next[0], next[1]) != 'a'
+ ) {
+ const afterNext = [next[0] + step[0], next[1] + step[1]];
+ if (V.OnBoard(afterNext[0], afterNext[1])) {
+ const afterColor = this.getColor(afterNext[0], afterNext[1])
+ if (
+ this.board[afterNext[0]][afterNext[1]] == V.EMPTY ||
+ afterColor != color1
+ ) {
+ move.appear[0].x = afterNext[0];
+ move.appear[0].y = afterNext[1];
+ if (this.board[afterNext[0]][afterNext[1]] != V.EMPTY) {
+ // The "object" could also be an opponent's piece
+ const object = this.getPiece(afterNext[0], afterNext[1]);
+ move.vanish.push(
+ new PiPo({
+ x: afterNext[0],
+ y: afterNext[1],
+ c: afterColor,
+ p: object
+ })
+ );
+ switch (object) {
+ case V.BANANA:
+ case V.BOMB:
+ const steps =
+ V.steps[object == V.BANANA ? V.ROOK : V.BISHOP];
+ move.next = this.getRandomSquare(
+ [afterNext[0], afterNext[1]], steps);
+ break;
+ case V.EGG:
+ applyEggEffect();
+ break;
+ case V.MUSHROOM:
+ applyMushroomEffect();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ };
+ const color2 = this.getColor(x2, y2);
+ const piece2 = this.getPiece(x2, y2);
+ if (color2 == 'a') {
+ switch (piece2) {
+ case V.BANANA:
+ case V.BOMB:
+ const steps = V.steps[piece2 == V.BANANA ? V.ROOK : V.BISHOP];
+ move.next = this.getRandomSquare([x2, y2], steps);
+ break;
+ case V.MUSHROOM:
+ applyMushroomEffect();
+ break;
+ case V.EGG:
+ if (this.subTurn == 1)
+ // No egg effect at subTurn 2
+ applyEggEffect();
+ break;
+ }
+ }
+ if (
+ this.subTurn == 1 &&
+ !move.next &&
+ move.appear.length > 0 &&
+ [V.ROOK, V.BISHOP].includes(piece1)
+ ) {
+ const finalSquare = [move.appear[0].x, move.appear[0].y];
+ if (
+ color2 != 'a' ||
+ this.getColor(finalSquare[0], finalSquare[1]) != 'a' ||
+ this.getPiece(finalSquare[0], finalSquare[1]) != V.EGG
+ ) {
+ const validSteps =
+ V.steps[piece1 == V.ROOK ? V.BISHOP : V.ROOK].filter(s => {
+ const [i, j] = [finalSquare[0] + s[0], finalSquare[1] + s[1]];
+ return (
+ V.OnBoard(i, j) &&
+ (this.board[i][j] == V.EMPTY || this.getColor(i, j) == 'a')
+ );
+ });
+ if (validSteps.length >= 1) {
+ const [x, y] = [
+ finalSquare[0] + validSteps[0][0],
+ finalSquare[1] + validSteps[0][1]
+ ];
+ move.appear.push(
+ new PiPo({
+ x: x,
+ y: y,
+ c: 'a',
+ p: (piece1 == V.ROOK ? V.BANANA : V.BOMB)
+ })
+ );
+ if (this.board[x][y] != V.EMPTY) {
+ move.vanish.push(
+ new PiPo({ x: x, y: y, c: 'a', p: this.getPiece(x, y) }));
+ }
+ }
+ }
+ }
+ return move;