Fix handling of alt move plays.

This commit is contained in:
yukirij 2024-09-08 00:58:50 -07:00
parent 1dbe02966b
commit c39c05969e
15 changed files with 154 additions and 102 deletions

View File

@ -23,6 +23,9 @@ impl Column {
pub struct Tile { pub struct Tile {
pub piece:Option<u8>, pub piece:Option<u8>,
pub threat:[bool; 2], pub threat:[bool; 2],
pub check:bool,
pub hex:Hex,
} }
impl Tile { impl Tile {
pub fn new() -> Self pub fn new() -> Self
@ -30,6 +33,9 @@ impl Tile {
Self { Self {
piece:None, piece:None,
threat:[false; 2], threat:[false; 2],
check:false,
hex:Hex::new(),
} }
} }
} }
@ -81,7 +87,7 @@ impl Board {
(Piece::new(PIECE_DRAGON, PLAYER_DAWN), Hex::from_hex(4, 2)), (Piece::new(PIECE_DRAGON, PLAYER_DAWN), Hex::from_hex(4, 2)),
(Piece::new(PIECE_BEHEMOTH, PLAYER_DAWN), Hex::from_hex(4, 1)), (Piece::new(PIECE_BEHEMOTH, PLAYER_DAWN), Hex::from_hex(4, 1)),
(Piece::new(PIECE_OMEN, PLAYER_DAWN), Hex::from_hex(4, 0)), (Piece::new(PIECE_SOURCE, PLAYER_DAWN), Hex::from_hex(4, 0)),
]; ];
for (piece, hex) in &layout { for (piece, hex) in &layout {

View File

@ -11,4 +11,4 @@ pub const PIECE_TOWER :u8 = 3;
pub const PIECE_CASTLE :u8 = 4; pub const PIECE_CASTLE :u8 = 4;
pub const PIECE_DRAGON :u8 = 5; pub const PIECE_DRAGON :u8 = 5;
pub const PIECE_BEHEMOTH :u8 = 6; pub const PIECE_BEHEMOTH :u8 = 6;
pub const PIECE_OMEN :u8 = 7; pub const PIECE_SOURCE :u8 = 7;

View File

@ -50,6 +50,8 @@ impl Game {
if self.complete { return Err(()); } if self.complete { return Err(()); }
let valid = true;
// //
// TODO: // TODO:
// - Check for piece promotion. // - Check for piece promotion.
@ -58,85 +60,93 @@ impl Game {
// //
// Move piece on board. if valid {
if match play.source {
0 => {
if let Some(pid) = self.board.tiles[play.from as usize].piece {
if let Some(mut piece) = self.board.pieces[pid as usize] {
let mut swap = false;
if let Some(tid) = self.board.tiles[play.to as usize].piece { // Move piece on board.
if let Some(target) = &mut self.board.pieces[tid as usize] { if match play.source {
0 | 3 => {
if let Some(pid) = self.board.tiles[play.from as usize].piece {
if let Some(mut piece) = self.board.pieces[pid as usize] {
let mut swap = false;
// Check for piece swap. if let Some(tid) = self.board.tiles[play.to as usize].piece {
if piece.player == target.player { if let Some(target) = &mut self.board.pieces[tid as usize] {
swap = true;
target.tile = play.from;
// Check for target promotion. // Check for piece swap.
let hex = Hex::from_tile(play.from); if piece.player == target.player {
if !target.promoted && target.has_promotion() && Hex::is_back(hex.x, hex.y, target.player) { swap = true;
target.promoted = true; target.tile = play.from;
// Check for target promotion.
let hex = Hex::from_tile(play.from);
if !target.promoted && target.has_promotion() && Hex::is_back(hex.x, hex.y, target.player) {
target.promoted = true;
}
}
// Add captured piece to pool.
else {
self.pool[piece.player as usize][target.class as usize] += 1;
} }
} }
// Add captured piece to pool. // Destroy piece if captured.
else { if !swap { self.board.pieces[tid as usize] = None; }
self.pool[piece.player as usize][target.class as usize] += 1; }
// Set tile/piece associations.
if swap {
self.board.tiles[play.from as usize].piece = self.board.tiles[play.to as usize].piece;
} else {
self.board.tiles[play.from as usize].piece = None;
}
self.board.tiles[play.to as usize].piece = Some(pid);
piece.tile = play.to;
self.board.pieces[pid as usize] = Some(piece);
// Check for piece promotion.
let hex = Hex::from_tile(play.to);
if !piece.promoted && piece.has_promotion() && Hex::is_back(hex.x, hex.y, piece.player) {
if let Some(piece) = &mut self.board.pieces[pid as usize] {
piece.promoted = true;
} }
} }
// Destroy piece if captured. self.turn += 1;
if !swap { self.board.pieces[tid as usize] = None; } true
} } else { false }
} else { false }
}
// Set tile/piece associations. // Place piece from pool.
if swap { 1 => {
self.board.tiles[play.from as usize].piece = self.board.tiles[play.to as usize].piece; if self.pool[player as usize][play.from as usize] > 0 && self.board.tiles[play.to as usize].piece.is_none() {
} else { self.pool[player as usize][play.from as usize] -= 1;
self.board.tiles[play.from as usize].piece = None; let piece = Piece::new(play.from, player);
} self.board.set_piece(piece, play.to);
self.board.tiles[play.to as usize].piece = Some(pid);
piece.tile = play.to;
self.board.pieces[pid as usize] = Some(piece);
// Check for piece promotion.
let hex = Hex::from_tile(play.to);
if !piece.promoted && piece.has_promotion() && Hex::is_back(hex.x, hex.y, piece.player) {
if let Some(piece) = &mut self.board.pieces[pid as usize] {
piece.promoted = true;
}
}
self.turn += 1; self.turn += 1;
true true
} else { false } } else { false }
} else { false } }
}
// Place piece from pool. // Player retired.
1 => { 2 => {
if self.pool[player as usize][play.from as usize] > 0 && self.board.tiles[play.to as usize].piece.is_none() { self.complete = true;
self.pool[player as usize][play.from as usize] -= 1;
let piece = Piece::new(play.from, player);
self.board.set_piece(piece, play.to);
self.turn += 1;
true true
} else { false } }
}
// Player retired. _ => false,
2 => { } {
self.complete = true; self.history.push(*play);
true Ok(())
} } else { Err(()) }
_ => false,
} {
self.history.push(*play);
Ok(())
} else { Err(()) } } else { Err(()) }
} }
fn get_moves(_piece:&Piece) -> Vec<Play>
{
Vec::new()
}
} }

View File

@ -104,7 +104,7 @@ pub const PIECES :[PieceClass; PIECES_COUNT] = [
}, },
}, },
PieceClass { PieceClass {
name: "Omen", name: "Source",
moves: MoveSet { moves: MoveSet {
direction:0, direction:0,
stride:0, stride:0,

View File

@ -1,5 +1,6 @@
const ROWS :[u8; 10] = [ 0, 5, 11, 18, 26, 35, 43, 50, 56, 61 ]; const ROWS :[u8; 10] = [ 0, 5, 11, 18, 26, 35, 43, 50, 56, 61 ];
#[derive(Clone, Copy)]
pub struct Hex { pub struct Hex {
pub x:u8, pub x:u8,
pub y:u8, pub y:u8,

View File

@ -211,7 +211,7 @@ async fn main()
} }
} }
let about_path = std::path::Path::new("www/about"); let about_path = std::path::Path::new("www/pages/about");
for doc in [ for doc in [
"main", "main",
] { ] {
@ -220,7 +220,7 @@ async fn main()
} }
} }
let guide_path = std::path::Path::new("www/guide"); let guide_path = std::path::Path::new("www/pages/guide");
for doc in [ for doc in [
"game", "game",
"pieces", "pieces",

View File

@ -36,9 +36,9 @@ impl Packet for PacketGamePlay {
result.turn = unpack_u16(data, index); result.turn = unpack_u16(data, index);
let play = unpack_u16(data, index) as u32; let play = unpack_u16(data, index) as u32;
result.play.source = (play & mask(1, 0)) as u8; result.play.source = (play & mask(4, 0)) as u8;
result.play.from = ((play & mask(6, 1)) >> 1) as u8; result.play.from = ((play & mask(6, 4)) >> 4) as u8;
result.play.to = ((play & mask(6, 7)) >> 7) as u8; result.play.to = ((play & mask(6, 10)) >> 10) as u8;
Ok(result) Ok(result)
} }

View File

@ -151,11 +151,10 @@ GAME.MovementTile = class {
}; };
GAME.Play = class { GAME.Play = class {
constructor(source, from, to, alt=false) { constructor(source, from, to) {
this.source = source; this.source = source;
this.from = from; this.from = from;
this.to = to; this.to = to;
this.alt = alt;
} }
}; };
@ -347,7 +346,8 @@ GAME.Game = class {
// Move piece on board. // Move piece on board.
switch(play.source) { switch(play.source) {
case 0: { case 0:
case 3: {
let piece_id = this.board.tiles[play.from].piece; let piece_id = this.board.tiles[play.from].piece;
let piece = this.board.pieces[piece_id]; let piece = this.board.pieces[piece_id];
piece.tile = play.to; piece.tile = play.to;
@ -387,7 +387,7 @@ GAME.Game = class {
} }
// Handle alt moves. // Handle alt moves.
if(play.alt) { if(play.source == 3) {
switch(piece.piece) { switch(piece.piece) {
case GAME.Const.PieceId.Knight: { case GAME.Const.PieceId.Knight: {
piece.promoted = false; piece.promoted = false;

View File

@ -241,8 +241,13 @@ const INTERFACE = {
// Handle player action. // Handle player action.
switch(result) { switch(result) {
case 1: { case 1: {
let source = INTERFACE_DATA.select.source;
if(source == 0 && INTERFACE_DATA.alt_mode) {
source = 3;
}
let play = new GAME.Play( let play = new GAME.Play(
INTERFACE_DATA.select.source, source,
INTERFACE_DATA.select.tile, INTERFACE_DATA.select.tile,
INTERFACE_DATA.hover.tile, INTERFACE_DATA.hover.tile,
INTERFACE_DATA.alt_mode INTERFACE_DATA.alt_mode
@ -386,7 +391,7 @@ const INTERFACE = {
let draw_piece = true; let draw_piece = true;
if(INTERFACE_DATA.Animate.play !== null) { if(INTERFACE_DATA.Animate.play !== null) {
let play = INTERFACE_DATA.Animate.play; let play = INTERFACE_DATA.Animate.play;
draw_piece = draw_piece && !(play.source == 0 && (play.from == i || play.to == i)); draw_piece = draw_piece && !((play.source == 0 || play.source == 3) && (play.from == i || play.to == i));
draw_piece = draw_piece && !(play.source == 1 && play.to == i); draw_piece = draw_piece && !(play.source == 1 && play.to == i);
} }
@ -425,7 +430,7 @@ const INTERFACE = {
case 1: ctx.fillStyle = INTERFACE.Color.TileLight; break; case 1: ctx.fillStyle = INTERFACE.Color.TileLight; break;
case 2: ctx.fillStyle = INTERFACE.Color.TileDark; break; case 2: ctx.fillStyle = INTERFACE.Color.TileDark; break;
} }
if(GAME_DATA.turn > 0 && play.source < 2 && (play.to == i || (play.source == 0 && play.from == i))) { if(GAME_DATA.turn > 0 && (play.source < 2 || play.source == 3) && (play.to == i || ((play.source == 0 || play.source == 3) && play.from == i))) {
ctx.fillStyle = INTERFACE.Color.HintPlay; ctx.fillStyle = INTERFACE.Color.HintPlay;
} else if(GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Source && piece.player == (GAME_DATA.turn & 1)) { } else if(GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Source && piece.player == (GAME_DATA.turn & 1)) {
ctx.fillStyle = INTERFACE.Color.HintCheck; ctx.fillStyle = INTERFACE.Color.HintCheck;
@ -655,7 +660,8 @@ const INTERFACE = {
let from_y = 0; let from_y = 0;
switch(play.source) { switch(play.source) {
// Lerp between board positions. // Lerp between board positions.
case 0: { case 0:
case 3: {
let coord_from = HEX.tile_to_hex(play.from); let coord_from = HEX.tile_to_hex(play.from);
if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) { if((INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate == 1) {
coord_from.x = 8 - coord_from.x; coord_from.x = 8 - coord_from.x;
@ -1100,7 +1106,8 @@ const INTERFACE = {
let valid = true; let valid = true;
switch(play.source) { switch(play.source) {
case 0: { case 0:
case 3: {
let piece_id = GAME_DATA.board.tiles[play.from].piece; let piece_id = GAME_DATA.board.tiles[play.from].piece;
let piece = GAME_DATA.board.pieces[piece_id]; let piece = GAME_DATA.board.pieces[piece_id];
valid = piece.player == (GAME_DATA.turn & 1); valid = piece.player == (GAME_DATA.turn & 1);
@ -1134,7 +1141,7 @@ const INTERFACE = {
// Send action to server for validation. // Send action to server for validation.
case INTERFACE.Mode.Player: { case INTERFACE.Mode.Player: {
let move_data = play.source | (play.from << 1) | (play.to << 7); let move_data = play.source | (play.from << 4) | (play.to << 10);
MESSAGE_COMPOSE([ MESSAGE_COMPOSE([
PACK.u16(OpCode.GamePlay), PACK.u16(OpCode.GamePlay),
PACK.u16(0), PACK.u16(0),
@ -1211,26 +1218,32 @@ const INTERFACE = {
let target = null; let target = null;
while(INTERFACE_DATA.replay_turn < turn) { while(INTERFACE_DATA.replay_turn < turn) {
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn]; play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn];
if(play.source < 2) { switch(play.source) {
if(play.source == 0) { case 0:
let piece_id = GAME_DATA.board.tiles[play.from].piece; case 1:
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); } case 3: {
if(play.source == 0 || play.source == 3) {
let piece_id = GAME_DATA.board.tiles[play.from].piece;
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
piece_id = GAME_DATA.board.tiles[play.to].piece; piece_id = GAME_DATA.board.tiles[play.to].piece;
if(piece_id !== null) { target = GAME_DATA.board.pieces[piece_id].clone(); } if(piece_id !== null) { target = GAME_DATA.board.pieces[piece_id].clone(); }
else { target = null; } else { target = null; }
}
GAME_DATA.process(play);
if(play.source == 1) {
let piece_id = GAME_DATA.board.tiles[play.to].piece;
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
target = null;
}
} break;
default: {
GAME_DATA.process(play);
play = null;
} }
GAME_DATA.process(play);
if(play.source == 1) {
let piece_id = GAME_DATA.board.tiles[play.to].piece;
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
target = null;
}
} else {
GAME_DATA.process(play);
play = null;
} }
INTERFACE_DATA.replay_turn++; INTERFACE_DATA.replay_turn++;
} }

View File

@ -557,6 +557,17 @@ const SCENES = {
} }
}, },
Extras:class{
constructor() { }
load() {
UI.mainmenu("extras");
UI.mainnav([], []);
history.pushState(null, "Dzura - About", "/extras/");
return true;
}
},
Game:class{ Game:class{
constructor() { constructor() {
this.game = null; this.game = null;

View File

@ -165,7 +165,7 @@ const UI = {
top.push(UI.button(LANG("guide"), () => { LOAD(SCENES.Guide); }, page == "guide")); top.push(UI.button(LANG("guide"), () => { LOAD(SCENES.Guide); }, page == "guide"));
top.push(UI.button(LANG("about"), () => { LOAD(SCENES.About); }, page == "about")); top.push(UI.button(LANG("about"), () => { LOAD(SCENES.About); }, page == "about"));
bottom.push(UI.button(LANG("extras"), () => { })); bottom.push(UI.button(LANG("extras"), () => { LOAD(SCENES.Extras) }, page == "extras"));
if(sessionStorage.getItem("auth") !== null) { if(sessionStorage.getItem("auth") !== null) {
bottom.push(UI.button(LANG("account"), () => { })); bottom.push(UI.button(LANG("account"), () => { }));

View File

@ -11,6 +11,17 @@ Dzura is a work of [Project Kirisame](https://kirisame.com).
© 2024 Yukiri Corporation © 2024 Yukiri Corporation
## Guidelines
1. Be polite, respectful, and honorable.
### Bots
1. Bots are generally permitted, provided they abide by these rules.
2. While not manidatory, we prefer that bots be labeled as such (e.g. in their handles).
3. Bots should not initiate games or send challenges.
## User Privacy ## User Privacy
This website does not collect any information beyond that used to implement user accounts and gameplay. This website does not collect any information beyond that used to implement user accounts and gameplay.