784 lines
24 KiB
JavaScript
784 lines
24 KiB
JavaScript
const GAME = { };
|
|
let GAME_DATA = null;
|
|
|
|
GAME.Board = class {
|
|
constructor() {
|
|
this.tiles = [ ]; for(let i = 0; i < 61; ++i) { this.tiles.push(new GAME.Tile(i)); }
|
|
this.pieces = [ ]; for(let i = 0; i < GAME.Const.Count.Pieces; ++i) { this.pieces.push(null); }
|
|
this.columns = [ ]; for(let i = 0; i < 9; ++i) { this.columns.push(new GAME.Column()); }
|
|
|
|
this.init();
|
|
}
|
|
|
|
init() {
|
|
this.pieces = [ ]; for(let i = 0; i < GAME.Const.Count.Pieces; ++i) { this.pieces.push(null); }
|
|
|
|
// Describe Dawn layout
|
|
let layout = [
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(0, 1) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(1, 1) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(2, 2) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(3, 2) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(4, 3) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(5, 3) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(6, 4) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(7, 4) },
|
|
{ piece:GAME.Const.PieceId.Militia, hex:new MATH.Vec2(8, 5) },
|
|
|
|
{ piece:GAME.Const.PieceId.Lance, hex:new MATH.Vec2(0, 0) },
|
|
{ piece:GAME.Const.PieceId.Lance, hex:new MATH.Vec2(8, 4) },
|
|
|
|
{ piece:GAME.Const.PieceId.Knight, hex:new MATH.Vec2(1, 0) },
|
|
{ piece:GAME.Const.PieceId.Knight, hex:new MATH.Vec2(7, 3) },
|
|
|
|
{ piece:GAME.Const.PieceId.Castle, hex:new MATH.Vec2(2, 0) },
|
|
{ piece:GAME.Const.PieceId.Castle, hex:new MATH.Vec2(6, 2) },
|
|
|
|
{ piece:GAME.Const.PieceId.Tower, hex:new MATH.Vec2(3, 0) },
|
|
{ piece:GAME.Const.PieceId.Tower, hex:new MATH.Vec2(5, 1) },
|
|
|
|
{ piece:GAME.Const.PieceId.Dragon, hex:new MATH.Vec2(4, 2) },
|
|
{ piece:GAME.Const.PieceId.Behemoth, hex:new MATH.Vec2(4, 1) },
|
|
|
|
{ piece:GAME.Const.PieceId.Omen, hex:new MATH.Vec2(4, 0) },
|
|
];
|
|
|
|
// Add Dawn pieces
|
|
for(let lay of layout) {
|
|
this.set_piece(
|
|
lay.piece,
|
|
GAME.Const.Player.Dawn,
|
|
HEX.hex_to_tile(lay.hex)
|
|
);
|
|
}
|
|
|
|
// Add Dusk pieces
|
|
for(let lay of layout) {
|
|
this.set_piece(
|
|
lay.piece,
|
|
GAME.Const.Player.Dusk,
|
|
HEX.hex_to_tile(new MATH.Vec2(8 - lay.hex.x, 8 - lay.hex.y))
|
|
);
|
|
}
|
|
}
|
|
|
|
set_piece(piece, player, tile) {
|
|
let index = 0;
|
|
while(this.pieces[index] !== null) { index++; }
|
|
|
|
let game_piece = new GAME.Piece(piece, player);
|
|
game_piece.tile = tile;
|
|
this.tiles[tile].piece = index;
|
|
this.pieces[index] = game_piece;
|
|
return index;
|
|
}
|
|
|
|
reset() {
|
|
for(let i = 0; i < this.tiles.length; ++i) { this.tiles[i].reset(); }
|
|
for(let i = 0; i < this.columns.length; ++i) { this.columns[i].reset(); }
|
|
for(let i = 0; i < this.pieces.length; ++i) { if(this.pieces[i] !== null) { this.pieces[i].reset(); } }
|
|
}
|
|
};
|
|
|
|
GAME.Pool = class {
|
|
constructor() {
|
|
this.pieces = [ ]; for(let i = 0; i < 7; ++i) { this.pieces.push(0); }
|
|
}
|
|
};
|
|
|
|
GAME.Column = class {
|
|
constructor() {
|
|
this.militia = [false, false];
|
|
this.extent = [0, 8];
|
|
}
|
|
|
|
reset() {
|
|
this.militia = [false, false];
|
|
this.extent = [0, 8];
|
|
}
|
|
};
|
|
|
|
GAME.Tile = class {
|
|
constructor(index) {
|
|
this.piece = null;
|
|
|
|
this.threaten = [false, false];
|
|
this.checking = false;
|
|
|
|
this.hex = HEX.tile_to_hex(index);
|
|
}
|
|
|
|
reset() {
|
|
this.threaten = [false, false];
|
|
this.checking = false;
|
|
}
|
|
};
|
|
|
|
GAME.MovementTile = class {
|
|
constructor(tile, valid, threat, check, block) {
|
|
this.tile = tile;
|
|
this.valid = valid;
|
|
this.threat = threat;
|
|
this.check = check;
|
|
this.block = block;
|
|
}
|
|
};
|
|
|
|
GAME.Play = class {
|
|
constructor(source, from, to) {
|
|
this.source = source;
|
|
this.from = from;
|
|
this.to = to;
|
|
}
|
|
};
|
|
|
|
GAME.GamePiece = class {
|
|
constructor(name, moves, promote_moves=null) {
|
|
this.name = name;
|
|
this.moves = moves;
|
|
this.pmoves = promote_moves;
|
|
}
|
|
};
|
|
|
|
GAME.PieceMovement = class {
|
|
constructor() {
|
|
this.direction = 0;
|
|
this.stride = 0;
|
|
}
|
|
|
|
add(direction) {
|
|
this.direction |= 1 << direction;
|
|
return this;
|
|
}
|
|
|
|
add_stride(direction) {
|
|
this.direction |= 1 << direction;
|
|
this.stride |= 1 << direction;
|
|
return this;
|
|
}
|
|
|
|
rotate() {
|
|
let copy = new GAME.PieceMovement();
|
|
copy.direction = BITWISE.rotate_blocks(this.direction);
|
|
copy.stride = BITWISE.rotate_blocks(this.stride);
|
|
return copy;
|
|
}
|
|
};
|
|
|
|
GAME.Piece = class {
|
|
constructor(piece, player) {
|
|
this.piece = piece;
|
|
this.player = player;
|
|
this.promoted = false;
|
|
|
|
this.tile = 0;
|
|
this.blocking = 0;
|
|
}
|
|
|
|
moves() {
|
|
let def = GAME.Const.Piece[this.piece];
|
|
let moves = null;
|
|
if(this.promoted) { moves = def.pmoves; }
|
|
else { moves = def.moves; }
|
|
if(this.player == GAME.Const.Player.Dusk) { moves = moves.rotate(); }
|
|
return moves;
|
|
}
|
|
|
|
has_promotion() {
|
|
return !this.promoted && GAME.Const.Piece[this.piece].pmoves !== null;
|
|
}
|
|
|
|
reset() {
|
|
this.blocking = 0;
|
|
}
|
|
};
|
|
|
|
GAME.Game = class {
|
|
constructor() {
|
|
this.turn = 0;
|
|
|
|
this.board = new GAME.Board();
|
|
this.pools = [
|
|
new GAME.Pool(),
|
|
new GAME.Pool(),
|
|
];
|
|
|
|
this.state = {
|
|
code:0,
|
|
check:false,
|
|
checkmate:false,
|
|
};
|
|
|
|
this.update_board();
|
|
}
|
|
|
|
update_board() {
|
|
// Reset tiles
|
|
this.board.reset();
|
|
|
|
this.state.check = false;
|
|
this.state.checkmate = false;
|
|
|
|
// Determine threaten, check, and blocking for each piece
|
|
for(let piece of this.board.pieces) {
|
|
if(piece !== null) {
|
|
let hex = this.board.tiles[piece.tile].hex;
|
|
|
|
// Check if column has militia.
|
|
if(piece.piece == GAME.Const.PieceId.Militia && !piece.promoted) {
|
|
this.board.columns[hex.x].militia[piece.player] = true;
|
|
}
|
|
|
|
// Check furthest piece in column.
|
|
if(piece.player == 0) { this.board.columns[hex.x].extent[0] = Math.max(hex.y, this.board.columns[hex.x].extent[0]); }
|
|
else { this.board.columns[hex.x].extent[1] = Math.min(hex.y, this.board.columns[hex.x].extent[1]); }
|
|
|
|
// Get threatened tiles.
|
|
for(let movement of this.movement_tiles(piece, piece.tile)) {
|
|
if(movement.threat) {
|
|
this.board.tiles[movement.tile].threaten[piece.player] = true;
|
|
}
|
|
if(movement.check) {
|
|
this.board.tiles[piece.tile].checking = true;
|
|
this.board.tiles[movement.tile].checking = true;
|
|
this.state.check = true;
|
|
}
|
|
if(movement.block != 0) {
|
|
this.board.pieces[this.board.tiles[movement.tile].piece].blocking = movement.block;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Count moves available to next turn player to determine checkmate.
|
|
if(this.state.check) {
|
|
let moves = 0;
|
|
|
|
// Search for valid board moves.
|
|
for(let piece of this.board.pieces) {
|
|
if(piece !== null && piece.player == (this.turn & 1)) {
|
|
for(let move of this.movement_tiles(piece, piece.tile)) {
|
|
if(move.valid) { moves += 1; }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Search for valid pool placements.
|
|
for(let i = 0; i < this.pools[0].length; ++i) {
|
|
for(let move of this.placement_tiles(i, (this.turn & 1))) {
|
|
if(move.valid) { moves += 1; }
|
|
}
|
|
}
|
|
|
|
if(moves == 0) { this.state.checkmate = true; }
|
|
}
|
|
}
|
|
|
|
process(play) {
|
|
// Check if swapped piece.
|
|
// Check if piece should be promoted.
|
|
// Check if swapped piece should be promoted.
|
|
// Add piece to pool if taken.
|
|
// Move pieces.
|
|
|
|
// TODO
|
|
// - Validate move.
|
|
// - Improve data safety validation.
|
|
//
|
|
|
|
if(this.state.code != 0) { return false; }
|
|
|
|
let player = this.turn & 1;
|
|
|
|
// Move piece on board.
|
|
switch(play.source) {
|
|
case 0: {
|
|
let piece_id = this.board.tiles[play.from].piece;
|
|
let piece = this.board.pieces[piece_id];
|
|
piece.tile = play.to;
|
|
this.board.tiles[play.from].piece = null;
|
|
|
|
let target_id = this.board.tiles[play.to].piece;
|
|
if(target_id !== null) {
|
|
let target = this.board.pieces[target_id];
|
|
|
|
// Swap piece with moving piece.
|
|
if(target.player == piece.player) {
|
|
target.tile = play.from;
|
|
this.board.tiles[play.from].piece = target_id;
|
|
|
|
// Check if swap is promoted.
|
|
let hex = HEX.tile_to_hex(target.tile);
|
|
hex.y -= MATH.sign_branch(target.player);
|
|
if(!target.promoted && target.has_promotion() && !HEX.is_valid(hex)) {
|
|
target.promoted = true;
|
|
}
|
|
}
|
|
|
|
// Add captured piece to pool and destroy.
|
|
else {
|
|
this.pools[piece.player].pieces[target.piece] += 1;
|
|
this.board.pieces[target_id] = null;
|
|
}
|
|
}
|
|
|
|
this.board.tiles[play.to].piece = piece_id;
|
|
|
|
// Check if piece is promoted.
|
|
let hex = HEX.tile_to_hex(piece.tile);
|
|
hex.y -= MATH.sign_branch(piece.player);
|
|
if(!piece.promoted && piece.has_promotion() && !HEX.is_valid(hex)) {
|
|
piece.promoted = true;
|
|
}
|
|
this.turn++;
|
|
} break;
|
|
|
|
// Place piece from pool.
|
|
case 1: {
|
|
this.board.set_piece(
|
|
play.from,
|
|
player,
|
|
play.to
|
|
);
|
|
this.pools[this.turn & 1].pieces[play.from] -= 1;
|
|
this.turn++;
|
|
} break;
|
|
|
|
// Play retired.
|
|
case 2: {
|
|
this.state.code = 2;
|
|
} break;
|
|
}
|
|
|
|
// Recalculate new board state.
|
|
this.update_board();
|
|
|
|
// If check, detect checkmate.
|
|
}
|
|
|
|
movement_tiles(piece, tile) {
|
|
let tiles = [ ];
|
|
let moves = piece.moves();
|
|
let hex = this.board.tiles[tile].hex;
|
|
|
|
let directions = moves.direction;
|
|
let permitted_moves = directions;
|
|
let block_directions = piece.blocking;
|
|
if(block_directions != 0) {
|
|
block_directions |= BITWISE.rotate_blocks(piece.blocking);
|
|
//if(piece.piece != GAME.Const.PieceId.Omen) {
|
|
// permitted_moves &= piece.blocking;
|
|
//}
|
|
}
|
|
|
|
// Check directions of movement.
|
|
for(let mask = BITWISE.lsb(directions); directions > 0; mask = BITWISE.lsb(directions)) {
|
|
let direction_id = BITWISE.ffs(mask);
|
|
let direction = GAME.Const.get_direction(direction_id);
|
|
let stride = (moves.stride & mask) != 0;
|
|
|
|
// Get initial status in direction.
|
|
let valid = (permitted_moves & mask) != 0;
|
|
let pieces_blocking = 0;
|
|
|
|
let move_hex = hex.copy();
|
|
|
|
// Check tiles in direction up to movement limit.
|
|
let max_dist = (stride)? 8 : 1;
|
|
for(let dist = 1; dist <= max_dist; ++dist) {
|
|
move_hex.add(direction);
|
|
|
|
let threat = valid;
|
|
let check = false;
|
|
let block = 0;
|
|
let swap = false;
|
|
let tile_occupied = false;
|
|
|
|
if(HEX.is_valid(move_hex)) {
|
|
let tile_id = HEX.hex_to_tile(move_hex);
|
|
let tile_data = this.board.tiles[tile_id];
|
|
|
|
let result = valid;
|
|
|
|
// Prevent moves that do not uncheck the King.
|
|
if(piece.player == (this.turn & 1)
|
|
&& this.state.check && !tile_data.checking
|
|
&& piece.piece != GAME.Const.PieceId.Omen) {
|
|
result = false;
|
|
}
|
|
|
|
// King may not move onto threatened tile.
|
|
if(piece.piece == GAME.Const.PieceId.Omen && tile_data.threaten[+(!piece.player)]) {
|
|
result = false;
|
|
}
|
|
|
|
// Handle occupied tile.
|
|
if(tile_data.piece !== null) {
|
|
let target = this.board.pieces[tile_data.piece];
|
|
tile_occupied = true;
|
|
|
|
// Target piece is ally.
|
|
if(target.player == piece.player) {
|
|
pieces_blocking += 2;
|
|
|
|
// Move is only valid if pieces are swappable.
|
|
if(this.movement_swappable(piece, target, mask, dist, tile)) {
|
|
swap = true;
|
|
} else {
|
|
result = false;
|
|
}
|
|
valid = false;
|
|
}
|
|
|
|
// Target piece is opposing.
|
|
else {
|
|
// Check if target piece is opposing king.
|
|
if(target.piece == GAME.Const.PieceId.Omen) {
|
|
if(valid) {
|
|
check = true;
|
|
block = mask;
|
|
|
|
// Apply check to previous moves.
|
|
for(let idist = 1; idist < dist; idist++) {
|
|
tiles[tiles.length - idist].check = true;
|
|
}
|
|
}
|
|
|
|
if(pieces_blocking == 1) {
|
|
// Apply blocking to last .
|
|
for(let idist = 1; idist < dist; idist++) {
|
|
if(GAME_DATA.board.tiles[tiles[tiles.length - idist].tile].piece !== null) {
|
|
tiles[tiles.length - idist].block = mask;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
pieces_blocking += 1;
|
|
valid = false;
|
|
}
|
|
}
|
|
|
|
// Handle blocking restrictions.
|
|
if(block_directions != 0) {
|
|
if(piece.piece == GAME.Const.PieceId.Omen) {
|
|
result = result && ((mask & block_directions) == 0 || tile_occupied);
|
|
} else {
|
|
result = result && ((mask & block_directions) != 0 || swap);
|
|
}
|
|
}
|
|
|
|
tiles.push(new GAME.MovementTile(tile_id, result, threat, check, block));
|
|
} else { break; }
|
|
}
|
|
|
|
directions &= ~mask;
|
|
}
|
|
|
|
return tiles;
|
|
}
|
|
|
|
movement_swappable(piece, target, mask, range, tile) {
|
|
if(piece.piece == target.piece && piece.promoted == target.promoted) {
|
|
return false;
|
|
}
|
|
|
|
mask = BITWISE.rotate_blocks(mask);
|
|
let moves = target.moves();
|
|
|
|
// King cannot swap onto tile that is threatened.
|
|
// This case should also cover blocking.
|
|
if(target.piece == GAME.Const.PieceId.Omen
|
|
&& (this.board.tiles[tile].threaten[+(!target.player)] || piece.blocking != 0)) {
|
|
return false;
|
|
}
|
|
return ((moves.direction & mask) != 0 && (range == 1 || (moves.stride & mask) != 0));
|
|
}
|
|
|
|
placement_tiles(piece_id, player) {
|
|
let tiles = [ ];
|
|
let piece = new GAME.Piece(piece_id, player);
|
|
|
|
// Get tiles onto which piece may be placed.
|
|
for(let i = 0; i < this.board.tiles.length; ++i) {
|
|
let hex = HEX.tile_to_hex(i);
|
|
let tile = this.board.tiles[i];
|
|
let valid = false;
|
|
|
|
// Check if tile is occupied.
|
|
if(tile.piece === null) {
|
|
let position_valid = true;
|
|
|
|
if(player == (this.turn & 1) && this.state.check && !tile.checking) {
|
|
position_valid = false;
|
|
}
|
|
|
|
// Check off-sides.
|
|
if(piece.player == 0) {
|
|
position_valid = position_valid && (hex.y <= this.board.columns[hex.x].extent[+(!player)]);
|
|
} else {
|
|
position_valid = position_valid && (hex.y >= this.board.columns[hex.x].extent[+(!player)]);
|
|
}
|
|
|
|
// Check militia stacking.
|
|
if(piece_id == GAME.Const.PieceId.Militia && this.board.columns[hex.x].militia[player]) {
|
|
position_valid = false;
|
|
}
|
|
|
|
// Check if position puts king in check.
|
|
let checking = false;
|
|
let movements = this.movement_tiles(piece, i);
|
|
for(let movement of movements) {
|
|
if(movement.check) {
|
|
checking = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Piece must have movements and not put king in check.
|
|
if(position_valid && movements.length > 0 && !checking) {
|
|
valid = true;
|
|
}
|
|
}
|
|
|
|
tiles.push(new GAME.MovementTile(i, valid, false, false));
|
|
}
|
|
|
|
return tiles;
|
|
}
|
|
};
|
|
|
|
GAME.Const = {
|
|
Player: {
|
|
Dawn: 0,
|
|
Dusk: 1,
|
|
},
|
|
|
|
Source: {
|
|
Board: 0,
|
|
Pool: 1,
|
|
},
|
|
|
|
State: {
|
|
Ongoing: 0,
|
|
Complete: 1,
|
|
Retire: 2,
|
|
},
|
|
|
|
Direction: [
|
|
new MATH.Vec2(0, 1),
|
|
new MATH.Vec2(1, 1),
|
|
new MATH.Vec2(1, 0),
|
|
new MATH.Vec2(0, -1),
|
|
new MATH.Vec2(-1, -1),
|
|
new MATH.Vec2(-1, 0),
|
|
|
|
new MATH.Vec2(1, 2),
|
|
new MATH.Vec2(2, 1),
|
|
new MATH.Vec2(1, -1),
|
|
new MATH.Vec2(-1, -2),
|
|
new MATH.Vec2(-2, -1),
|
|
new MATH.Vec2(-1, 1),
|
|
|
|
/*new MATH.Vec2(1, 3),
|
|
new MATH.Vec2(2, 3),
|
|
new MATH.Vec2(3, 2),
|
|
new MATH.Vec2(3, 1),
|
|
new MATH.Vec2(2, -1),
|
|
new MATH.Vec2(1, -2),
|
|
new MATH.Vec2(-1, -3),
|
|
new MATH.Vec2(-2, -3),
|
|
new MATH.Vec2(-3, -2),
|
|
new MATH.Vec2(-3, -1),
|
|
new MATH.Vec2(-2, 1),
|
|
new MATH.Vec2(-1, 2),*/
|
|
],
|
|
|
|
MoveStatus: {
|
|
Valid: 0,
|
|
Invalid: 1,
|
|
Check: 2,
|
|
},
|
|
|
|
PieceId: {
|
|
Militia: 0,
|
|
Lance: 1,
|
|
Knight: 2,
|
|
Tower: 3,
|
|
Castle: 4,
|
|
Dragon: 5,
|
|
Behemoth: 6,
|
|
Omen: 7,
|
|
},
|
|
|
|
Count: {
|
|
Pieces:40,
|
|
},
|
|
|
|
Piece: [
|
|
new GAME.GamePiece(
|
|
"Militia",
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(5),
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(3)
|
|
.add(4)
|
|
.add(5),
|
|
),
|
|
new GAME.GamePiece(
|
|
"Lance",
|
|
new GAME.PieceMovement()
|
|
.add_stride(0)
|
|
.add(1)
|
|
.add(5),
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(3)
|
|
.add(4)
|
|
.add(5),
|
|
),
|
|
new GAME.GamePiece(
|
|
"Knight",
|
|
new GAME.PieceMovement()
|
|
.add(6)
|
|
.add(8)
|
|
.add(9)
|
|
.add(11)
|
|
.add(13)
|
|
.add(14)
|
|
.add(16)
|
|
.add(17),
|
|
/*new GAME.PieceMovement()
|
|
.add(12)
|
|
.add(13)
|
|
.add(14)
|
|
.add(15)
|
|
.add(16)
|
|
.add(17)
|
|
.add(18)
|
|
.add(19)
|
|
.add(20)
|
|
.add(21)
|
|
.add(22)
|
|
.add(23),*/
|
|
),
|
|
new GAME.GamePiece(
|
|
"Tower",
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(3)
|
|
.add(5)
|
|
.add(6)
|
|
.add(11),
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(3)
|
|
.add(4)
|
|
.add(5)
|
|
.add(6)
|
|
.add(8)
|
|
.add(9)
|
|
.add(11),
|
|
),
|
|
new GAME.GamePiece(
|
|
"Castle",
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(4)
|
|
.add(5)
|
|
.add(7)
|
|
.add(10),
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(3)
|
|
.add(4)
|
|
.add(5)
|
|
.add_stride(7)
|
|
.add_stride(10),
|
|
),
|
|
new GAME.GamePiece(
|
|
"Dragon",
|
|
new GAME.PieceMovement()
|
|
.add_stride(6)
|
|
.add_stride(7)
|
|
.add_stride(8)
|
|
.add_stride(9)
|
|
.add_stride(10)
|
|
.add_stride(11),
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(3)
|
|
.add(4)
|
|
.add(5)
|
|
.add_stride(6)
|
|
.add_stride(7)
|
|
.add_stride(8)
|
|
.add_stride(9)
|
|
.add_stride(10)
|
|
.add_stride(11),
|
|
),
|
|
new GAME.GamePiece(
|
|
"Behemoth",
|
|
new GAME.PieceMovement()
|
|
.add_stride(0)
|
|
.add_stride(1)
|
|
.add_stride(2)
|
|
.add_stride(3)
|
|
.add_stride(4)
|
|
.add_stride(5),
|
|
new GAME.PieceMovement()
|
|
.add_stride(0)
|
|
.add_stride(1)
|
|
.add_stride(2)
|
|
.add_stride(3)
|
|
.add_stride(4)
|
|
.add_stride(5)
|
|
.add(12)
|
|
.add(13)
|
|
.add(14)
|
|
.add(15)
|
|
.add(16)
|
|
.add(17)
|
|
),
|
|
new GAME.GamePiece(
|
|
"Omen",
|
|
new GAME.PieceMovement()
|
|
.add(0)
|
|
.add(1)
|
|
.add(2)
|
|
.add(3)
|
|
.add(4)
|
|
.add(5)
|
|
.add(7)
|
|
.add(10),
|
|
),
|
|
],
|
|
|
|
get_direction(direction_id) {
|
|
let direction = GAME.Const.Direction[direction_id % GAME.Const.Direction.length].copy();
|
|
direction.mul(Math.ceil((direction_id + 1) / GAME.Const.Direction.length));
|
|
return direction;
|
|
},
|
|
};
|
|
|
|
GAME.init = () => {
|
|
GAME_DATA = new GAME.Game();
|
|
};
|