Update piece names; remove check restriction from alt moves.
@ -5,10 +5,20 @@ use crate::{
|
||||
piece::Piece, util::Hex,
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
enum GameStatus {
|
||||
Normal,
|
||||
Check(u32),
|
||||
Checkmate,
|
||||
Resign,
|
||||
}
|
||||
|
||||
pub type Pool = [u8; 7];
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Game {
|
||||
pub complete:bool,
|
||||
status:GameStatus,
|
||||
|
||||
pub turn:u16,
|
||||
pub board:Board,
|
||||
pub pool:[Pool; 2],
|
||||
@ -19,7 +29,7 @@ impl Game {
|
||||
pub fn new() -> Self
|
||||
{
|
||||
Self {
|
||||
complete:false,
|
||||
status:GameStatus::Normal,
|
||||
|
||||
turn:0,
|
||||
|
||||
@ -48,7 +58,10 @@ impl Game {
|
||||
{
|
||||
let player = (self.turn & 1) as u8;
|
||||
|
||||
if self.complete { return Err(()); }
|
||||
match self.status {
|
||||
GameStatus::Checkmate | GameStatus::Resign => { return Err(()); }
|
||||
_ => { }
|
||||
}
|
||||
|
||||
let valid = true;
|
||||
|
||||
@ -133,7 +146,7 @@ impl Game {
|
||||
|
||||
// Player retired.
|
||||
2 => {
|
||||
self.complete = true;
|
||||
self.status = GameStatus::Resign;
|
||||
true
|
||||
}
|
||||
|
||||
@ -149,4 +162,12 @@ impl Game {
|
||||
{
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
pub fn is_complete(&self) -> bool
|
||||
{
|
||||
match self.status {
|
||||
GameStatus::Checkmate | GameStatus::Resign => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +238,7 @@ impl App {
|
||||
|
||||
// Add to resume if session has user and is user turn.
|
||||
let is_turn_player = (session.p_dawn.user == user_id && (session.game.turn & 1) == 0) || (session.p_dusk.user == user_id && (session.game.turn & 1) == 1);
|
||||
if !session.game.complete && is_turn_player {
|
||||
if !session.game.is_complete() && is_turn_player {
|
||||
response.resume += 1;
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ async fn main()
|
||||
for asset in [
|
||||
"promote.svg",
|
||||
|
||||
"omen_dawn.svg",
|
||||
"heart_dawn.svg",
|
||||
"behemoth_dawn.svg",
|
||||
"dragon_dawn.svg",
|
||||
"castle_dawn.svg",
|
||||
@ -197,7 +197,7 @@ async fn main()
|
||||
"knight_dawn.svg",
|
||||
"militia_dawn.svg",
|
||||
|
||||
"omen_dusk.svg",
|
||||
"heart_dusk.svg",
|
||||
"behemoth_dusk.svg",
|
||||
"dragon_dusk.svg",
|
||||
"castle_dusk.svg",
|
||||
|
@ -362,9 +362,9 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
if let Some(session) = app.sessions.get(token) {
|
||||
|
||||
let mut valid = match request.game_state {
|
||||
1 => !session.game.complete,
|
||||
2 => !session.game.complete,
|
||||
3 => session.game.complete,
|
||||
1 => !session.game.is_complete(),
|
||||
2 => !session.game.is_complete(),
|
||||
3 => session.game.is_complete(),
|
||||
_ => true,
|
||||
};
|
||||
valid &= !request.is_player || Some(session.p_dawn.user) == user_id || Some(session.p_dusk.user) == user_id;
|
||||
@ -473,7 +473,7 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
};
|
||||
|
||||
if let Some(session) = app.sessions.get_mut(&request.token) {
|
||||
if !session.game.complete {
|
||||
if !session.game.is_complete() {
|
||||
if (user_id == Some(session.p_dawn.user) && session.game.turn & 1 == 0)
|
||||
|| (user_id == Some(session.p_dusk.user) && session.game.turn & 1 == 1) {
|
||||
|
||||
@ -548,7 +548,7 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
||||
|
||||
if let Some(sid) = session_id {
|
||||
if let Some(session) = app.sessions.get_mut(&sid) {
|
||||
if !session.game.complete {
|
||||
if !session.game.is_complete() {
|
||||
if (user_id == Some(session.p_dawn.user) && session.game.turn & 1 == 0)
|
||||
|| (user_id == Some(session.p_dusk.user) && session.game.turn & 1 == 1) {
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
version="1.1"
|
||||
id="svg1"
|
||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
||||
sodipodi:docname="king_dawn.svg"
|
||||
sodipodi:docname="heart_dawn.svg"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@ -75,9 +75,9 @@
|
||||
sodipodi:nodetypes="ccccccccccccccc" />
|
||||
<path
|
||||
style="fill:#ffe082;fill-opacity:1"
|
||||
d="M 50,40 60,50 70,40 75,30 V 25 L 60,15 45,25 v 5 z"
|
||||
d="M 50,40 60,50 70,40 75,30 v -5 l -5,-5 -10,-5 -10,5 -5,5 v 5 z"
|
||||
id="path13"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
sodipodi:nodetypes="ccccccccccc" />
|
||||
<path
|
||||
style="fill:#ffe082;fill-opacity:1"
|
||||
d="m 35,35 -5,5 5,5 5,-5 z"
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
www/asset/png/behemoth-dawn.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
www/asset/png/behemoth-dusk.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
www/asset/png/castle-dawn.png
Normal file
After Width: | Height: | Size: 916 B |
BIN
www/asset/png/castle-dusk.png
Normal file
After Width: | Height: | Size: 932 B |
BIN
www/asset/png/dragon-dawn.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
www/asset/png/dragon-dusk.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
www/asset/png/heart-dawn.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
www/asset/png/heart-dusk.png
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
www/asset/png/knight-dawn.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
www/asset/png/knight-dusk.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
www/asset/png/lance-dawn.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
www/asset/png/lance-dusk.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
www/asset/png/militia-dawn.png
Normal file
After Width: | Height: | Size: 886 B |
BIN
www/asset/png/militia-dusk.png
Normal file
After Width: | Height: | Size: 911 B |
BIN
www/asset/png/tower-dawn.png
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
www/asset/png/tower-dusk.png
Normal file
After Width: | Height: | Size: 2.4 KiB |
@ -40,7 +40,7 @@ GAME.Board = class {
|
||||
{ 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.Source, hex:new MATH.Vec2(4, 0) },
|
||||
{ piece:GAME.Const.PieceId.Heart, hex:new MATH.Vec2(4, 0) },
|
||||
];
|
||||
|
||||
// Add Dawn pieces
|
||||
@ -170,7 +170,7 @@ GAME.PieceMovement = class {
|
||||
constructor() {
|
||||
this.direction = 0;
|
||||
this.stride = 0;
|
||||
this.alt = false;
|
||||
this.alt = 0;
|
||||
}
|
||||
|
||||
add(direction) {
|
||||
@ -184,8 +184,8 @@ GAME.PieceMovement = class {
|
||||
return this;
|
||||
}
|
||||
|
||||
add_alt() {
|
||||
this.alt = true;
|
||||
add_alt(id) {
|
||||
this.alt = id;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -353,6 +353,8 @@ GAME.Game = class {
|
||||
piece.tile = play.to;
|
||||
this.board.tiles[play.from].piece = null;
|
||||
|
||||
let moves = piece.moves();
|
||||
|
||||
let target_id = this.board.tiles[play.to].piece;
|
||||
if(target_id !== null) {
|
||||
let target = this.board.pieces[target_id];
|
||||
@ -388,8 +390,8 @@ GAME.Game = class {
|
||||
|
||||
// Handle alt moves.
|
||||
if(play.source == 3) {
|
||||
switch(piece.piece) {
|
||||
case GAME.Const.PieceId.Knight: {
|
||||
switch(moves.alt) {
|
||||
case 0: {
|
||||
piece.promoted = false;
|
||||
} break;
|
||||
}
|
||||
@ -471,7 +473,7 @@ GAME.Game = class {
|
||||
let check_direct = (this.state.check & 0x040) != 0;
|
||||
let check_count = this.state.check & 0x3F;
|
||||
if(piece.player == (this.turn & 1) && this.state.check != 0) {
|
||||
if(piece.piece != GAME.Const.PieceId.Source) {
|
||||
if(piece.piece != GAME.Const.PieceId.Heart) {
|
||||
if(tile_data.checking != 0) {
|
||||
if(target_id !== null) {
|
||||
if(check_count > 1) {
|
||||
@ -487,7 +489,7 @@ GAME.Game = class {
|
||||
}
|
||||
|
||||
// King may not move onto threatened tile.
|
||||
if(piece.piece == GAME.Const.PieceId.Source && tile_data.threaten[+(!piece.player)] > 0) {
|
||||
if(piece.piece == GAME.Const.PieceId.Heart && tile_data.threaten[+(!piece.player)] > 0) {
|
||||
result = false;
|
||||
}
|
||||
|
||||
@ -512,7 +514,7 @@ GAME.Game = class {
|
||||
// Target piece is opposing.
|
||||
else {
|
||||
// Check if target piece is opposing king.
|
||||
if(target.piece == GAME.Const.PieceId.Source) {
|
||||
if(target.piece == GAME.Const.PieceId.Heart) {
|
||||
if(valid) {
|
||||
if(dist == 1) { check = GAME.Const.Check.Direct; }
|
||||
else { check = GAME.Const.Check.Stride; }
|
||||
@ -543,7 +545,7 @@ GAME.Game = class {
|
||||
|
||||
// Handle blocking restrictions.
|
||||
if(block_directions != 0) {
|
||||
if(piece.piece == GAME.Const.PieceId.Source) {
|
||||
if(piece.piece == GAME.Const.PieceId.Heart) {
|
||||
result = result && ((dir_mask & block_directions) == 0 || tile_occupied);
|
||||
} else {
|
||||
result = result && ((dir_mask & block_directions) != 0 || swap);
|
||||
@ -570,7 +572,7 @@ GAME.Game = class {
|
||||
|
||||
// King cannot swap onto tile that is threatened.
|
||||
// This case should also cover blocking.
|
||||
if(target.piece == GAME.Const.PieceId.Source
|
||||
if(target.piece == GAME.Const.PieceId.Heart
|
||||
&& (this.board.tiles[tile].threaten[+(!target.player)] > 0 || piece.blocking != 0)) {
|
||||
return false;
|
||||
}
|
||||
@ -584,9 +586,12 @@ GAME.Game = class {
|
||||
let hex = this.board.tiles[piece.tile].hex;
|
||||
let block_directions = piece.blocking | BITWISE.rotate_blocks6(piece.blocking);
|
||||
|
||||
switch(piece.piece) {
|
||||
case GAME.Const.PieceId.Knight: {
|
||||
let moves = piece.moves();
|
||||
|
||||
switch(moves.alt) {
|
||||
/* Drop Once */ case 1:
|
||||
/* Drop Cone */ case 2:
|
||||
{
|
||||
// Check all tiles if not blocking.
|
||||
if(block_directions == 0) {
|
||||
for(let i = 0; i < GAME_DATA.board.tiles.length; ++i) {
|
||||
@ -615,7 +620,7 @@ GAME.Game = class {
|
||||
|
||||
if(target_id !== null) { break; }
|
||||
|
||||
if(this.placable_tile(piece, tile_id)) {
|
||||
if(this.placable_tile(piece, tile_id, {check:false})) {
|
||||
tiles.push(new GAME.MovementTile(tile_id, true, false, 0, 0));
|
||||
}
|
||||
} else { break; }
|
||||
@ -626,7 +631,7 @@ GAME.Game = class {
|
||||
}
|
||||
} break;
|
||||
|
||||
case GAME.Const.PieceId.Castle: {
|
||||
case 3: {
|
||||
|
||||
// Check all tiles if not blocking.
|
||||
if(block_directions == 0) {
|
||||
@ -718,7 +723,7 @@ GAME.Game = class {
|
||||
return tiles;
|
||||
}
|
||||
|
||||
placable_tile(piece, tile_id) {
|
||||
placable_tile(piece, tile_id, params={}) {
|
||||
let valid = false;
|
||||
|
||||
let hex = HEX.tile_to_hex(tile_id);
|
||||
@ -753,11 +758,13 @@ GAME.Game = class {
|
||||
|
||||
// Check if position puts king in check.
|
||||
let checking = false;
|
||||
let movements = this.movement_tiles(piece, tile_id, true);
|
||||
for(let movement of movements) {
|
||||
if(movement.check) {
|
||||
checking = true;
|
||||
break;
|
||||
if(params.check !== false) {
|
||||
let movements = this.movement_tiles(piece, tile_id, true);
|
||||
for(let movement of movements) {
|
||||
if(movement.check) {
|
||||
checking = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -817,7 +824,7 @@ GAME.Const = {
|
||||
Castle: 4,
|
||||
Dragon: 5,
|
||||
Behemoth: 6,
|
||||
Source: 7,
|
||||
Heart: 7,
|
||||
},
|
||||
|
||||
Count: {
|
||||
@ -874,7 +881,7 @@ GAME.Const = {
|
||||
.add(14)
|
||||
.add(16)
|
||||
.add(17)
|
||||
.add_alt(),
|
||||
.add_alt(1),
|
||||
),
|
||||
new GAME.GamePiece(
|
||||
"Tower",
|
||||
@ -916,7 +923,7 @@ GAME.Const = {
|
||||
.add(5)
|
||||
.add(7)
|
||||
.add(10)
|
||||
.add_alt(),
|
||||
.add_alt(2),
|
||||
),
|
||||
new GAME.GamePiece(
|
||||
"Dragon",
|
||||
@ -965,7 +972,7 @@ GAME.Const = {
|
||||
.add(17)
|
||||
),
|
||||
new GAME.GamePiece(
|
||||
"Source",
|
||||
"Heart",
|
||||
new GAME.PieceMovement()
|
||||
.add(0)
|
||||
.add(1)
|
||||
|
@ -16,6 +16,6 @@ GAME_ASSET.Image = {
|
||||
[ GAME_ASSET.load_image("/asset/castle_dawn.svg"), GAME_ASSET.load_image("/asset/castle_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/dragon_dawn.svg"), GAME_ASSET.load_image("/asset/dragon_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/behemoth_dawn.svg"), GAME_ASSET.load_image("/asset/behemoth_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/omen_dawn.svg"), GAME_ASSET.load_image("/asset/omen_dusk.svg") ],
|
||||
[ GAME_ASSET.load_image("/asset/heart_dawn.svg"), GAME_ASSET.load_image("/asset/heart_dusk.svg") ],
|
||||
],
|
||||
};
|
||||
|
19
www/js/game_config.js
Normal file
@ -0,0 +1,19 @@
|
||||
class GameConfig {
|
||||
constructor() {
|
||||
this.key = new Uint8Array(4);
|
||||
this.name = "";
|
||||
//this.user = 0;
|
||||
|
||||
this.pieces = [ ];
|
||||
this.layout = [ ];
|
||||
this.pools = new Uint8Array(14);
|
||||
|
||||
this.actions = [ ];
|
||||
this.states = [ ];
|
||||
}
|
||||
}
|
||||
|
||||
GameConfig.State = class {
|
||||
//this.name = "";
|
||||
|
||||
};
|
@ -64,7 +64,7 @@ LANGUAGE.Terms = {
|
||||
accept: new LANGUAGE.Term( "Accept", "受け入れ" ),
|
||||
decline: new LANGUAGE.Term( "Decline", "断る" ),
|
||||
|
||||
play: new LANGUAGE.Term( "Play", "遣る" ),
|
||||
play: new LANGUAGE.Term( "Play", "続く" ),
|
||||
|
||||
check: new LANGUAGE.Term( "Check", "王手" ),
|
||||
checkmate: new LANGUAGE.Term( "Checkmate", "詰み" ),
|
||||
@ -76,7 +76,7 @@ LANGUAGE.Terms = {
|
||||
Castle: new LANGUAGE.Term( "Castle", "城" ),
|
||||
Dragon: new LANGUAGE.Term( "Dragon", "竜" ),
|
||||
Behemoth: new LANGUAGE.Term( "Behemoth", "獣" ),
|
||||
Source: new LANGUAGE.Term( "Source", "元" ),
|
||||
Heart: new LANGUAGE.Term( "Heart", "元" ),
|
||||
|
||||
|
||||
//: new LANGUAGE.Term( "", "" ),
|
||||
|
@ -649,7 +649,7 @@ const SCENES = {
|
||||
UI.mainnav(
|
||||
[ ],
|
||||
[
|
||||
UI.button("Auto", () => { INTERFACE.replay_toggle_auto(); }),
|
||||
UI.button(LANG("auto"), () => { INTERFACE.replay_toggle_auto(); }),
|
||||
UI.button("◀", () => { INTERFACE.replay_off(); INTERFACE.replay_first(); }),
|
||||
UI.button("◁", () => { INTERFACE.replay_off(); INTERFACE.replay_prev(); }),
|
||||
ind_turn,
|
||||
|