Rework game messages; change images to raw vector graphics.
@ -77,7 +77,7 @@ impl Game {
|
|||||||
|
|
||||||
// Move piece on board.
|
// Move piece on board.
|
||||||
if match play.source {
|
if match play.source {
|
||||||
0 | 3 => {
|
0 | 2 => {
|
||||||
if let Some(pid) = self.board.tiles[play.from as usize].piece {
|
if let Some(pid) = self.board.tiles[play.from as usize].piece {
|
||||||
if let Some(mut piece) = self.board.pieces[pid as usize] {
|
if let Some(mut piece) = self.board.pieces[pid as usize] {
|
||||||
let mut swap = false;
|
let mut swap = false;
|
||||||
@ -144,12 +144,6 @@ impl Game {
|
|||||||
} else { false }
|
} else { false }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player retired.
|
|
||||||
2 => {
|
|
||||||
self.status = GameStatus::Resign;
|
|
||||||
true
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
} {
|
} {
|
||||||
self.history.push(*play);
|
self.history.push(*play);
|
||||||
|
@ -21,6 +21,7 @@ rust-argon2 = "2.1.0"
|
|||||||
ring = "0.17.8"
|
ring = "0.17.8"
|
||||||
const_format = "0.2.32"
|
const_format = "0.2.32"
|
||||||
markdown = "0.3.0"
|
markdown = "0.3.0"
|
||||||
|
usvg = "0.44.0"
|
||||||
|
|
||||||
game = { path = "../game" }
|
game = { path = "../game" }
|
||||||
|
|
||||||
|
@ -87,6 +87,10 @@ impl App {
|
|||||||
|
|
||||||
// Load session history
|
// Load session history
|
||||||
if let Ok(history) = filesystem.session_history_fetch(id as u32) {
|
if let Ok(history) = filesystem.session_history_fetch(id as u32) {
|
||||||
|
let mut history = history;
|
||||||
|
for play in &mut history {
|
||||||
|
if play.source == 3 { play.source = 2; }
|
||||||
|
}
|
||||||
session.game.apply_history(&history).ok();
|
session.game.apply_history(&history).ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,9 +197,9 @@ impl App {
|
|||||||
)).await.ok();
|
)).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
QRPacketData::QGamePlay(response) => {
|
QRPacketData::GameMessage(response) => {
|
||||||
socket.send(Message::Binary(
|
socket.send(Message::Binary(
|
||||||
encode_response(CODE_GAME_PLAY, response.encode())
|
encode_response(CODE_GAME_MESSAGE, response.encode())
|
||||||
)).await.ok();
|
)).await.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,6 +22,8 @@ pub struct Session {
|
|||||||
|
|
||||||
pub time:u64,
|
pub time:u64,
|
||||||
pub chain_id:usize,
|
pub chain_id:usize,
|
||||||
|
|
||||||
|
pub undo:Option<u8>,
|
||||||
}
|
}
|
||||||
impl Session {
|
impl Session {
|
||||||
pub fn get_connections(&self) -> Vec<(u32, u8)>
|
pub fn get_connections(&self) -> Vec<(u32, u8)>
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
use bus::Bus;
|
use bus::Bus;
|
||||||
|
|
||||||
@ -159,68 +160,71 @@ async fn main()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load image assets
|
||||||
|
let mut js_asset_data = String::from("const GAME_ASSET = { Image: {");
|
||||||
|
let asset_path = Path::new("www/asset/");
|
||||||
|
for name in [
|
||||||
|
"Promote",
|
||||||
|
"Militia",
|
||||||
|
"Lance",
|
||||||
|
"Knight",
|
||||||
|
"Tower",
|
||||||
|
"Castle",
|
||||||
|
"Dragon",
|
||||||
|
"Behemoth",
|
||||||
|
"Heart",
|
||||||
|
] {
|
||||||
|
if let Ok(output) = util::imager::load(asset_path.join(&format!("{}.svg", name))) {
|
||||||
|
js_asset_data += &format!("{}:{},", name, output);
|
||||||
|
} else {
|
||||||
|
println!("error: failed to load asset: {}", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
js_asset_data += "} };";
|
||||||
|
|
||||||
// Initialize HTTPS service.
|
// Initialize HTTPS service.
|
||||||
match b_main.connect() {
|
match b_main.connect() {
|
||||||
Ok(bus) => {
|
Ok(bus) => {
|
||||||
let cache = WebCache::new();
|
let cache = WebCache::new();
|
||||||
cache.cache_file("text/html", "/.html", "www/.html").ok();
|
cache.cache("text/html", "/.html", &[
|
||||||
|
WebCache::file("www/.html"),
|
||||||
|
]).ok();
|
||||||
cache.cache_whitespace_minimize("/.html").ok();
|
cache.cache_whitespace_minimize("/.html").ok();
|
||||||
cache.cache_file_group("text/css", "/.css", &[
|
cache.cache("text/css", "/.css", &[
|
||||||
"www/css/main.css",
|
WebCache::file("www/css/main.css"),
|
||||||
"www/css/ui.css",
|
WebCache::file("www/css/ui.css"),
|
||||||
"www/css/form.css",
|
WebCache::file("www/css/form.css"),
|
||||||
"www/css/game.css",
|
WebCache::file("www/css/game.css"),
|
||||||
"www/css/util.css",
|
WebCache::file("www/css/util.css"),
|
||||||
]).ok();
|
]).ok();
|
||||||
cache.cache_file_group("text/javascript", "/.js", &[
|
cache.cache("text/javascript", "/.js", &[
|
||||||
"www/js/const.js",
|
WebCache::file("www/js/const.js"),
|
||||||
"www/js/language.js",
|
WebCache::file("www/js/language.js"),
|
||||||
"www/js/util.js",
|
WebCache::file("www/js/util.js"),
|
||||||
"www/js/badge.js",
|
WebCache::file("www/js/badge.js"),
|
||||||
"www/js/game_asset.js",
|
WebCache::file("www/js/game_asset.js"),
|
||||||
"www/js/game.js",
|
WebCache::string(&js_asset_data),
|
||||||
"www/js/interface.js",
|
WebCache::file("www/js/game.js"),
|
||||||
"www/js/ui.js",
|
WebCache::file("www/js/interface.js"),
|
||||||
"www/js/scene.js",
|
WebCache::file("www/js/ui.js"),
|
||||||
"www/js/system.js",
|
WebCache::file("www/js/scene.js"),
|
||||||
"www/js/main.js",
|
WebCache::file("www/js/system.js"),
|
||||||
|
WebCache::file("www/js/main.js"),
|
||||||
|
]).ok();
|
||||||
|
cache.cache("image/png", "/favicon.png", &[
|
||||||
|
WebCache::file("www/asset/favicon.png"),
|
||||||
|
]).ok();
|
||||||
|
cache.cache("image/png", "/favicon_notify.png", &[
|
||||||
|
WebCache::file("www/asset/favicon_notify.png"),
|
||||||
]).ok();
|
]).ok();
|
||||||
cache.cache_file("image/png", "/favicon.png", "www/asset/favicon.png").ok();
|
|
||||||
cache.cache_file("image/png", "/favicon_notify.png", "www/asset/favicon_notify.png").ok();
|
|
||||||
|
|
||||||
let asset_path = std::path::Path::new("www/asset");
|
|
||||||
for asset in [
|
|
||||||
"promote.svg",
|
|
||||||
|
|
||||||
"heart_dawn.svg",
|
|
||||||
"behemoth_dawn.svg",
|
|
||||||
"dragon_dawn.svg",
|
|
||||||
"castle_dawn.svg",
|
|
||||||
"tower_dawn.svg",
|
|
||||||
"lance_dawn.svg",
|
|
||||||
"knight_dawn.svg",
|
|
||||||
"militia_dawn.svg",
|
|
||||||
|
|
||||||
"heart_dusk.svg",
|
|
||||||
"behemoth_dusk.svg",
|
|
||||||
"dragon_dusk.svg",
|
|
||||||
"castle_dusk.svg",
|
|
||||||
"tower_dusk.svg",
|
|
||||||
"lance_dusk.svg",
|
|
||||||
"knight_dusk.svg",
|
|
||||||
"militia_dusk.svg",
|
|
||||||
] {
|
|
||||||
if cache.cache_file("image/svg+xml", &format!("/asset/{}", asset), asset_path.join(asset)).is_err() {
|
|
||||||
println!("error: failed to load: {}", asset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let about_path = std::path::Path::new("www/pages/about");
|
let about_path = std::path::Path::new("www/pages/about");
|
||||||
for doc in [
|
for doc in [
|
||||||
"main",
|
"main",
|
||||||
] {
|
] {
|
||||||
if cache.cache_md(&format!("/about/{}.html", doc), about_path.join(format!("{}.md", doc))).is_err() {
|
if cache.cache("text/html", &format!("/about/{}.html", doc), &[
|
||||||
|
WebCache::markdown(about_path.join(format!("{}.md", doc)))
|
||||||
|
]).is_err() {
|
||||||
println!("error: failed to load: {}", doc);
|
println!("error: failed to load: {}", doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -231,7 +235,9 @@ async fn main()
|
|||||||
"pieces",
|
"pieces",
|
||||||
"interface",
|
"interface",
|
||||||
] {
|
] {
|
||||||
if cache.cache_md(&format!("/guide/{}.html", doc), guide_path.join(format!("{}.md", doc))).is_err() {
|
if cache.cache("text/html", &format!("/guide/{}.html", doc), &[
|
||||||
|
WebCache::markdown(guide_path.join(format!("{}.md", doc))),
|
||||||
|
]).is_err() {
|
||||||
println!("error: failed to load: {}", doc);
|
println!("error: failed to load: {}", doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use bus::Bus;
|
use bus::Bus;
|
||||||
|
use game::history::Play;
|
||||||
use crate::{
|
use crate::{
|
||||||
config,
|
config,
|
||||||
app::{
|
app::{
|
||||||
@ -554,10 +555,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
for (cid, _) in session.get_connections() {
|
for (cid, _) in session.get_connections() {
|
||||||
packets.push(QRPacket::new(
|
packets.push(QRPacket::new(
|
||||||
cid,
|
cid,
|
||||||
QRPacketData::QGamePlay(PacketGamePlay {
|
QRPacketData::GameMessage(PacketGameMessage {
|
||||||
status: STATUS_OK,
|
data: GameMessageData::Retire,
|
||||||
turn: session.game.turn,
|
|
||||||
play,
|
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -607,58 +606,114 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
Some(QRPacket::new(qr.id, QRPacketData::RGameState(response)))
|
Some(QRPacket::new(qr.id, QRPacketData::RGameState(response)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GamePlay
|
// GameMessage
|
||||||
QRPacketData::QGamePlay(mut request) => {
|
QRPacketData::GameMessage(request) => {
|
||||||
println!("Request: Game Play");
|
println!("Request: Game Message");
|
||||||
|
|
||||||
request.status = STATUS_ERROR;
|
|
||||||
let mut packets = Vec::<QRPacket>::new();
|
let mut packets = Vec::<QRPacket>::new();
|
||||||
|
|
||||||
if let Some(sid) = session_id {
|
if let Some(sid) = session_id {
|
||||||
if let Some(session) = app.sessions.get_mut(&sid) {
|
if let Some(session) = app.sessions.get_mut(&sid) {
|
||||||
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) {
|
|
||||||
|
|
||||||
// Check validation of play
|
match request.data {
|
||||||
if request.turn == session.game.turn {
|
GameMessageData::PlayMove(turn, from, to)
|
||||||
|
| GameMessageData::PlayDrop(turn, from, to)
|
||||||
|
| GameMessageData::PlayAlt(turn, from, to)
|
||||||
|
=> {
|
||||||
|
println!("HERE");
|
||||||
|
|
||||||
// Update internal representation
|
if !session.game.is_complete() {
|
||||||
if session.game.process(&request.play).is_ok() {
|
if (user_id == Some(session.p_dawn.user) && session.game.turn & 1 == 0)
|
||||||
request.status = STATUS_OK;
|
|| (user_id == Some(session.p_dusk.user) && session.game.turn & 1 == 1) {
|
||||||
|
if turn == session.game.turn {
|
||||||
|
let play = Play {
|
||||||
|
source: match request.data {
|
||||||
|
GameMessageData::PlayMove(..) => 0,
|
||||||
|
GameMessageData::PlayDrop(..) => 1,
|
||||||
|
GameMessageData::PlayAlt(..) => 2,
|
||||||
|
_ => 0,
|
||||||
|
},
|
||||||
|
from, to,
|
||||||
|
};
|
||||||
|
|
||||||
// Save play to game history.
|
println!("play {} {} {}", play.source, play.from, play.to);
|
||||||
app.filesystem.session_history_push(session.id, request.play).ok();
|
|
||||||
|
|
||||||
// Forward play to all clients
|
if session.game.process(&play).is_ok() {
|
||||||
for (cid, _) in session.get_connections() {
|
// Commit play to history
|
||||||
packets.push(QRPacket::new(
|
app.filesystem.session_history_push(session.id, play).ok();
|
||||||
cid,
|
|
||||||
QRPacketData::QGamePlay(request.clone())
|
// Forward messsage to all clients
|
||||||
));
|
for (cid, _) in session.get_connections() {
|
||||||
|
packets.push(QRPacket::new(
|
||||||
|
cid,
|
||||||
|
QRPacketData::GameMessage(request.clone())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send status to players.
|
||||||
|
send_user_status.push(session.p_dawn.user);
|
||||||
|
send_user_status.push(session.p_dusk.user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send status to players.
|
|
||||||
send_user_status.push(session.p_dawn.user);
|
|
||||||
send_user_status.push(session.p_dusk.user);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameMessageData::Undo(turn, _) => {
|
||||||
|
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) {
|
||||||
|
if turn == session.game.turn {
|
||||||
|
// Request or commit undo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMessageData::Retire => {
|
||||||
|
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) {
|
||||||
|
|
||||||
|
// Forward messsage to all clients
|
||||||
|
for (cid, _) in session.get_connections() {
|
||||||
|
packets.push(QRPacket::new(
|
||||||
|
cid,
|
||||||
|
QRPacketData::GameMessage(request.clone())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMessageData::Reaction(_) => {
|
||||||
|
|
||||||
|
// Forward messsage to all clients
|
||||||
|
for (cid, _) in session.get_connections() {
|
||||||
|
packets.push(QRPacket::new(
|
||||||
|
cid,
|
||||||
|
QRPacketData::GameMessage(request.clone())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => { }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if request.status != STATUS_ERROR {
|
match request.data {
|
||||||
for packet in packets {
|
GameMessageData::Error => {
|
||||||
app.send_response(packet).await;
|
Some(QRPacket::new(qr.id, QRPacketData::GameMessage(request)))
|
||||||
}
|
}
|
||||||
|
_ => {
|
||||||
|
for packet in packets {
|
||||||
|
app.send_response(packet).await;
|
||||||
|
}
|
||||||
|
|
||||||
// Updates will have already been sent, so nothing is needed here.
|
// Updates already sent; nothing to do here.
|
||||||
Some(QRPacket::new(qr.id, QRPacketData::None))
|
Some(QRPacket::new(qr.id, QRPacketData::None))
|
||||||
} else {
|
}
|
||||||
|
|
||||||
// Return error status.
|
|
||||||
Some(QRPacket::new(qr.id, QRPacketData::QGamePlay(request)))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -745,6 +800,8 @@ pub async fn thread_system(mut app:App, bus:Bus<protocol::QRPacket>)
|
|||||||
connections:Vec::new(),
|
connections:Vec::new(),
|
||||||
time:std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as u64,
|
time:std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as u64,
|
||||||
chain_id,
|
chain_id,
|
||||||
|
|
||||||
|
undo:None,
|
||||||
};
|
};
|
||||||
session.game.init();
|
session.game.init();
|
||||||
|
|
||||||
|
@ -156,11 +156,11 @@ pub async fn handle_ws(ws:WebSocketStream<TokioIo<Upgraded>>, args:HttpServiceAr
|
|||||||
Err(_) => { println!("error: packet decode failed."); }
|
Err(_) => { println!("error: packet decode failed."); }
|
||||||
}
|
}
|
||||||
|
|
||||||
CODE_GAME_PLAY => match PacketGamePlay::decode(&data, &mut index) {
|
CODE_GAME_MESSAGE => match PacketGameMessage::decode(&data, &mut index) {
|
||||||
Ok(packet) => {
|
Ok(packet) => {
|
||||||
args.bus.send(
|
args.bus.send(
|
||||||
bus_ds,
|
bus_ds,
|
||||||
QRPacket::new(conn_id, QRPacketData::QGamePlay(packet))
|
QRPacket::new(conn_id, QRPacketData::GameMessage(packet))
|
||||||
).ok();
|
).ok();
|
||||||
}
|
}
|
||||||
Err(_) => { println!("error: packet decode failed."); }
|
Err(_) => { println!("error: packet decode failed."); }
|
||||||
|
@ -38,7 +38,7 @@ pub const CODE_SESSION_RETIRE :u16 = 0x002E;
|
|||||||
pub const CODE_SESSION_LEAVE :u16 = 0x002F;
|
pub const CODE_SESSION_LEAVE :u16 = 0x002F;
|
||||||
|
|
||||||
pub const CODE_GAME_STATE :u16 = 0x0030;
|
pub const CODE_GAME_STATE :u16 = 0x0030;
|
||||||
pub const CODE_GAME_PLAY :u16 = 0x0031;
|
pub const CODE_GAME_MESSAGE :u16 = 0x0031;
|
||||||
|
|
||||||
pub const CODE_CHALLENGE :u16 = 0x0060;
|
pub const CODE_CHALLENGE :u16 = 0x0060;
|
||||||
pub const CODE_CHALLENGE_ANSWER :u16 = 0x0061;
|
pub const CODE_CHALLENGE_ANSWER :u16 = 0x0061;
|
||||||
@ -47,3 +47,17 @@ pub const CODE_CHALLENGE_LIST :u16 = 0x0062;
|
|||||||
pub const CODE_USER_LIST :u16 = 0x0100;
|
pub const CODE_USER_LIST :u16 = 0x0100;
|
||||||
//pub const CODE_USER_AWAIT_GET :u16 = 0x0110;
|
//pub const CODE_USER_AWAIT_GET :u16 = 0x0110;
|
||||||
//pub const CODE_USER_AWAIT_SET :u16 = 0x0111;
|
//pub const CODE_USER_AWAIT_SET :u16 = 0x0111;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Game Messages
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub const GMSG_ERROR :u8 = 0x00;
|
||||||
|
pub const GMSG_PLAY_MOVE :u8 = 0x01;
|
||||||
|
pub const GMSG_PLAY_DROP :u8 = 0x02;
|
||||||
|
pub const GMSG_PLAY_ALT :u8 = 0x03;
|
||||||
|
pub const GMSG_ONLINE :u8 = 0x08;
|
||||||
|
pub const GMSG_UNDO :u8 = 0x10;
|
||||||
|
pub const GMSG_RETIRE :u8 = 0x11;
|
||||||
|
pub const GMSG_REACTION :u8 = 0x20;
|
||||||
|
@ -42,7 +42,7 @@ pub enum QRPacketData {
|
|||||||
QGameState(PacketGameState),
|
QGameState(PacketGameState),
|
||||||
RGameState(PacketGameStateResponse),
|
RGameState(PacketGameStateResponse),
|
||||||
|
|
||||||
QGamePlay(PacketGamePlay),
|
GameMessage(PacketGameMessage),
|
||||||
|
|
||||||
QChallenge(PacketChallenge),
|
QChallenge(PacketChallenge),
|
||||||
|
|
||||||
|
128
server/src/protocol/packet/game_message.rs
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
use crate::{
|
||||||
|
util::pack::{
|
||||||
|
pack_u64,
|
||||||
|
unpack_u64,
|
||||||
|
},
|
||||||
|
protocol::*,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::Packet;
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
pub enum GameMessageData {
|
||||||
|
Error,
|
||||||
|
|
||||||
|
PlayMove(u16, u8, u8),
|
||||||
|
PlayDrop(u16, u8, u8),
|
||||||
|
PlayAlt(u16, u8, u8),
|
||||||
|
|
||||||
|
Online(u8, u32),
|
||||||
|
|
||||||
|
Undo(u16, u8),
|
||||||
|
Retire,
|
||||||
|
|
||||||
|
Reaction(u16),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct PacketGameMessage {
|
||||||
|
pub data:GameMessageData,
|
||||||
|
}
|
||||||
|
impl PacketGameMessage {
|
||||||
|
pub fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
data:GameMessageData::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Packet for PacketGameMessage {
|
||||||
|
type Data = Self;
|
||||||
|
|
||||||
|
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
||||||
|
{
|
||||||
|
let mut result = Self::new();
|
||||||
|
|
||||||
|
if data.len() - *index >= 8 {
|
||||||
|
let data = unpack_u64(data, index);
|
||||||
|
result.data = match (data & 0xFF) as u8 {
|
||||||
|
GMSG_PLAY_MOVE => GameMessageData::PlayMove(
|
||||||
|
((data >> 8) & 0xFFFF) as u16,
|
||||||
|
((data >> 24) & 0x3F) as u8,
|
||||||
|
((data >> 30) & 0x3F) as u8,
|
||||||
|
),
|
||||||
|
GMSG_PLAY_DROP => GameMessageData::PlayDrop(
|
||||||
|
((data >> 8) & 0xFFFF) as u16,
|
||||||
|
((data >> 24) & 0x3F) as u8,
|
||||||
|
((data >> 30) & 0x3F) as u8,
|
||||||
|
),
|
||||||
|
GMSG_PLAY_ALT => GameMessageData::PlayAlt(
|
||||||
|
((data >> 8) & 0xFFFF) as u16,
|
||||||
|
((data >> 24) & 0x3F) as u8,
|
||||||
|
((data >> 30) & 0x3F) as u8,
|
||||||
|
),
|
||||||
|
|
||||||
|
GMSG_UNDO => GameMessageData::Undo(
|
||||||
|
((data >> 8) & 0xFFFF) as u16,
|
||||||
|
((data >> 24) & 0x1) as u8,
|
||||||
|
),
|
||||||
|
|
||||||
|
GMSG_RETIRE => GameMessageData::Retire,
|
||||||
|
|
||||||
|
GMSG_REACTION => GameMessageData::Reaction(
|
||||||
|
((data >> 8) & 0xFFFF) as u16,
|
||||||
|
),
|
||||||
|
|
||||||
|
_ => GameMessageData::Error,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encode(&self) -> Vec<u8>
|
||||||
|
{
|
||||||
|
pack_u64(match self.data {
|
||||||
|
GameMessageData::PlayMove(turn, from, to) => {
|
||||||
|
GMSG_PLAY_MOVE as u64
|
||||||
|
| ((turn as u64) << 8)
|
||||||
|
| ((from as u64) << 24)
|
||||||
|
| ((to as u64) << 30)
|
||||||
|
}
|
||||||
|
GameMessageData::PlayDrop(turn, piece, to) => {
|
||||||
|
GMSG_PLAY_DROP as u64
|
||||||
|
| ((turn as u64) << 8)
|
||||||
|
| ((piece as u64) << 24)
|
||||||
|
| ((to as u64) << 30)
|
||||||
|
}
|
||||||
|
GameMessageData::PlayAlt(turn, from, to) => {
|
||||||
|
GMSG_PLAY_ALT as u64
|
||||||
|
| ((turn as u64) << 8)
|
||||||
|
| ((from as u64) << 24)
|
||||||
|
| ((to as u64) << 30)
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMessageData::Online(client, state) => {
|
||||||
|
GMSG_PLAY_ALT as u64
|
||||||
|
| ((client as u64) << 8)
|
||||||
|
| ((state as u64) << 10)
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMessageData::Undo(turn, state) => {
|
||||||
|
GMSG_UNDO as u64
|
||||||
|
| ((turn as u64) << 8)
|
||||||
|
| ((state as u64) << 24)
|
||||||
|
}
|
||||||
|
GameMessageData::Retire => {
|
||||||
|
GMSG_RETIRE as u64
|
||||||
|
}
|
||||||
|
|
||||||
|
GameMessageData::Reaction(index) => {
|
||||||
|
GMSG_REACTION as u64
|
||||||
|
| ((index as u64) << 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => { 0 }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -1,58 +0,0 @@
|
|||||||
use crate::util::pack::{
|
|
||||||
pack_u16,
|
|
||||||
unpack_u16,
|
|
||||||
};
|
|
||||||
use game::{
|
|
||||||
history::Play,
|
|
||||||
util::mask,
|
|
||||||
};
|
|
||||||
|
|
||||||
use super::Packet;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct PacketGamePlay {
|
|
||||||
pub status:u16,
|
|
||||||
pub turn:u16,
|
|
||||||
pub play:Play,
|
|
||||||
}
|
|
||||||
impl PacketGamePlay {
|
|
||||||
pub fn new() -> Self
|
|
||||||
{
|
|
||||||
Self {
|
|
||||||
status:0,
|
|
||||||
turn:0,
|
|
||||||
play:Play::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Packet for PacketGamePlay {
|
|
||||||
type Data = Self;
|
|
||||||
|
|
||||||
fn decode(data:&Vec<u8>, index:&mut usize) -> Result<Self::Data, ()>
|
|
||||||
{
|
|
||||||
let mut result = Self::new();
|
|
||||||
|
|
||||||
result.status = unpack_u16(data, index);
|
|
||||||
result.turn = unpack_u16(data, index);
|
|
||||||
|
|
||||||
let play = unpack_u16(data, index) as u32;
|
|
||||||
result.play.source = (play & mask(4, 0)) as u8;
|
|
||||||
result.play.from = ((play & mask(6, 4)) >> 4) as u8;
|
|
||||||
result.play.to = ((play & mask(6, 10)) >> 10) as u8;
|
|
||||||
|
|
||||||
Ok(result)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode(&self) -> Vec<u8>
|
|
||||||
{
|
|
||||||
let mut data = 0;
|
|
||||||
data |= self.play.source as u16;
|
|
||||||
data |= (self.play.from as u16) << 4;
|
|
||||||
data |= (self.play.to as u16) << 10;
|
|
||||||
[
|
|
||||||
pack_u16(self.status),
|
|
||||||
pack_u16(self.turn),
|
|
||||||
pack_u16(data),
|
|
||||||
].concat()
|
|
||||||
}
|
|
||||||
}
|
|
@ -13,7 +13,7 @@ mod session_view; pub use session_view::*;
|
|||||||
mod session_retire; pub use session_retire::*;
|
mod session_retire; pub use session_retire::*;
|
||||||
|
|
||||||
mod game_state; pub use game_state::*;
|
mod game_state; pub use game_state::*;
|
||||||
mod game_play; pub use game_play::*;
|
mod game_message; pub use game_message::*;
|
||||||
//mod game_history; pub use game_history::*;
|
//mod game_history; pub use game_history::*;
|
||||||
|
|
||||||
mod challenge; pub use challenge::*;
|
mod challenge; pub use challenge::*;
|
||||||
|
102
server/src/system/cache/mod.rs
vendored
@ -9,6 +9,14 @@ use trie::Trie;
|
|||||||
|
|
||||||
use crate::util::string::minimize_whitespace;
|
use crate::util::string::minimize_whitespace;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub enum Source {
|
||||||
|
Raw(Vec<u8>),
|
||||||
|
String(String),
|
||||||
|
File(std::path::PathBuf),
|
||||||
|
MarkdownFile(std::path::PathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CacheData {
|
pub struct CacheData {
|
||||||
pub mime:String,
|
pub mime:String,
|
||||||
@ -46,55 +54,40 @@ impl WebCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache(&self, mime:&str, object:&str, data:Vec<u8>)
|
pub fn cache(&self, mime:&str, object:&str, sources:&[Source]) -> Result<(),()>
|
||||||
{
|
|
||||||
match self.data.write() {
|
|
||||||
Ok(mut writer) => {
|
|
||||||
writer.objects.set(object.as_bytes(), CacheData {
|
|
||||||
mime:mime.to_string(),
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
Err(_) => { },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cache_file<P :AsRef<Path>>(&self, mime:&str, object:&str, path:P) -> Result<(),()>
|
|
||||||
{
|
{
|
||||||
match self.data.write() {
|
match self.data.write() {
|
||||||
Ok(mut writer) => {
|
Ok(mut writer) => {
|
||||||
let mut data = Vec::new();
|
let mut data = Vec::new();
|
||||||
if let Ok(mut file) = File::open(path) {
|
|
||||||
file.read_to_end(&mut data).ok();
|
|
||||||
writer.objects.set(object.as_bytes(), CacheData {
|
|
||||||
mime:mime.to_string(),
|
|
||||||
data,
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
} else { Err(()) }
|
|
||||||
}
|
|
||||||
Err(_) => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cache_md<P :AsRef<Path>>(&self, object:&str, path:P) -> Result<(),()>
|
for source in sources {
|
||||||
{
|
match source {
|
||||||
match self.data.write() {
|
Source::Raw(raw) => {
|
||||||
Ok(mut writer) => {
|
data.append(&mut raw.clone());
|
||||||
match markdown::file_to_html(&path.as_ref()) {
|
}
|
||||||
Ok(text) => {
|
Source::String(text) => {
|
||||||
let text :Vec<String> = text.trim().lines().map(|line| line.trim().to_string()).collect();
|
data.append(&mut text.as_bytes().to_vec());
|
||||||
let data = text.concat().as_bytes().to_vec();
|
}
|
||||||
|
Source::File(path) => {
|
||||||
writer.objects.set(object.as_bytes(), CacheData {
|
let mut file_data = Vec::new();
|
||||||
mime:String::from("text/html"),
|
let mut file = File::open(path).map_err(|_| ())?;
|
||||||
data,
|
file.read_to_end(&mut file_data).ok();
|
||||||
});
|
data.append(&mut file_data);
|
||||||
Ok(())
|
}
|
||||||
|
Source::MarkdownFile(path) => {
|
||||||
|
let mut text = markdown::file_to_html(&path.as_ref()).map_err(|_| ())?;
|
||||||
|
text = text.trim().lines().map(|line| line.trim().to_string()).collect();
|
||||||
|
data.append(&mut text.as_bytes().to_vec());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(_) => Err(())
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
writer.objects.set(object.as_bytes(), CacheData {
|
||||||
|
mime:mime.to_string(),
|
||||||
|
data,
|
||||||
|
});
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
Err(_) => Err(()),
|
Err(_) => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,24 +105,9 @@ impl WebCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn cache_file_group<P :AsRef<Path>>(&self, mime:&str, object:&str, paths:&[P]) -> Result<(),()>
|
|
||||||
{
|
pub fn raw(data:Vec<u8>) -> Source { Source::Raw(data) }
|
||||||
match self.data.write() {
|
pub fn string(text:&str) -> Source { Source::String(text.to_string()) }
|
||||||
Ok(mut writer) => {
|
pub fn file<P :AsRef<Path>>(path:P) -> Source { Source::File((path.as_ref() as &Path).to_path_buf())}
|
||||||
let data = paths.into_iter().map(|path| {
|
pub fn markdown<P :AsRef<Path>>(path:P) -> Source { Source::MarkdownFile((path.as_ref() as &Path).to_path_buf())}
|
||||||
let mut buffer = Vec::new();
|
|
||||||
if let Ok(mut file) = File::open(path) {
|
|
||||||
file.read_to_end(&mut buffer).ok();
|
|
||||||
}
|
|
||||||
buffer
|
|
||||||
}).collect::<Vec<Vec<u8>>>().concat();
|
|
||||||
writer.objects.set(object.as_bytes(), CacheData {
|
|
||||||
mime:mime.to_string(),
|
|
||||||
data:data,
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
},
|
|
||||||
Err(_) => Err(()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -203,6 +203,8 @@ impl FileSystem {
|
|||||||
connections:Vec::new(),
|
connections:Vec::new(),
|
||||||
time,
|
time,
|
||||||
chain_id:0,
|
chain_id:0,
|
||||||
|
|
||||||
|
undo:None,
|
||||||
})
|
})
|
||||||
} else { Err(()) }
|
} else { Err(()) }
|
||||||
}
|
}
|
||||||
|
92
server/src/util/imager/mod.rs
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
use usvg::tiny_skia_path::PathSegment;
|
||||||
|
|
||||||
|
pub fn load<P :AsRef<Path>>(file:P) -> Result<String,()>
|
||||||
|
{
|
||||||
|
let mut output = String::from("new GameImage([");
|
||||||
|
|
||||||
|
let svg_data = std::fs::read(file).map_err(|_| ())?;
|
||||||
|
|
||||||
|
let opt = usvg::Options::default();
|
||||||
|
let rtree = usvg::Tree::from_data(&svg_data, &opt).map_err(|_| ())?;
|
||||||
|
|
||||||
|
let bounds = rtree.size();
|
||||||
|
let origin = [
|
||||||
|
bounds.width() / 2.,
|
||||||
|
bounds.height() / 2.,
|
||||||
|
];
|
||||||
|
let scale = 1. / bounds.width().max(bounds.height());
|
||||||
|
|
||||||
|
for node in rtree.root().children() {
|
||||||
|
output += &load_node(node, origin, scale)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += "])";
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_node(node:&usvg::Node, origin:[f32; 2], scale:f32) -> Result<String,()>
|
||||||
|
{
|
||||||
|
let mut output = String::new();
|
||||||
|
|
||||||
|
match &node {
|
||||||
|
usvg::Node::Group(group) => {
|
||||||
|
for node in group.children() {
|
||||||
|
output += &load_node(node, origin, scale)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
usvg::Node::Path(path) => {
|
||||||
|
output += "[";
|
||||||
|
output += &if let Some(fill) = path.fill() {
|
||||||
|
match fill.paint() {
|
||||||
|
usvg::Paint::Color(color) => {
|
||||||
|
format!("\"#{:02x}{:02x}{:02x}\"", color.red, color.green, color.blue)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
String::from("\"#000000\"")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String::from("\"#000000\"")
|
||||||
|
};
|
||||||
|
output += ",[";
|
||||||
|
|
||||||
|
for ref segment in path.data().segments() {
|
||||||
|
match segment {
|
||||||
|
PathSegment::MoveTo(point) => {
|
||||||
|
output += &format!("[0, [{:.4},{:.4}]],",
|
||||||
|
(point.x - origin[0]) * scale,
|
||||||
|
(point.y - origin[1]) * scale,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PathSegment::LineTo(point) => {
|
||||||
|
output += &format!("[1, [{:.4},{:.4}]],",
|
||||||
|
(point.x - origin[0]) * scale,
|
||||||
|
(point.y - origin[1]) * scale,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PathSegment::CubicTo(a, b, c) => {
|
||||||
|
output += &format!("[2, [{:.4},{:.4},{:.4},{:.4},{:.4},{:.4},]],",
|
||||||
|
(a.x - origin[0]) * scale,
|
||||||
|
(a.y - origin[1]) * scale,
|
||||||
|
(b.x - origin[0]) * scale,
|
||||||
|
(b.y - origin[1]) * scale,
|
||||||
|
(c.x - origin[0]) * scale,
|
||||||
|
(c.y - origin[1]) * scale,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PathSegment::Close => {
|
||||||
|
output += "[3],";
|
||||||
|
}
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output += "]],";
|
||||||
|
}
|
||||||
|
_ => { }
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(output)
|
||||||
|
}
|
||||||
|
|
@ -3,3 +3,4 @@ pub mod color;
|
|||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod pack;
|
pub mod pack;
|
||||||
mod chain; pub use chain::Chain;
|
mod chain; pub use chain::Chain;
|
||||||
|
pub mod imager;
|
||||||
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
@ -1,86 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="behemoth_dusk.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="6.9591091"
|
|
||||||
inkscape:cx="32.259876"
|
|
||||||
inkscape:cy="64.088663"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707108"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
id="path1"
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 41 21 L 35 23 L 33 26 L 31 32 L 31 37 L 32 41 L 31 44 L 28 46 L 25 43 L 24 35 L 25 29 L 27 24 L 23 27 L 21 30 L 20 34 L 19 40 L 20 47 L 24 52 L 30 53 L 36 52 L 39 47 L 40 43 L 42 44 L 44 49 L 45 55 L 41 70 L 39 77 L 36 80 L 32 81 L 28 78 L 26 75 L 26 71 L 27 65 L 23 70 L 22 75 L 23 81 L 27 85 L 35 87 L 41 85 L 46 80 L 54 70 L 60 55 L 66 70 L 74 80 L 79 85 L 85 87 L 93 85 L 97 81 L 98 75 L 97 70 L 93 65 L 94 71 L 94 75 L 92 78 L 88 81 L 84 80 L 81 77 L 79 70 L 75 55 L 76 49 L 78 44 L 80 43 L 81 47 L 84 52 L 90 53 L 96 52 L 100 47 L 101 40 L 100 34 L 99 30 L 97 27 L 93 24 L 95 29 L 96 35 L 95 43 L 92 46 L 89 44 L 88 41 L 89 37 L 89 32 L 87 26 L 85 23 L 79 21 L 71 23 L 67 28 L 63 33 L 60 40 L 57 33 L 53 28 L 49 23 L 41 21 z " />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 60,62 -2,8 -3,5 -3,4 -3,3 2,5 2,5 4,3 h 6 l 4,-3 2,-5 2,-5 -3,-3 -3,-4 -3,-5 z"
|
|
||||||
id="path3"
|
|
||||||
sodipodi:nodetypes="cccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 79,49 -1,6 1,6 3,8 2,-4 1,-4 -1,-6 -3,-2 z"
|
|
||||||
id="path4"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 41,49 1,6 -1,6 -3,8 -2,-4 -1,-4 1,-6 3,-2 z"
|
|
||||||
id="path4-7"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 3.1 KiB |
@ -1,82 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="castle_dusk.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="6.9591092"
|
|
||||||
inkscape:cx="46.198442"
|
|
||||||
inkscape:cy="46.845076"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707108"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
style="display:inline;fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 23,95 V 75 l 2,-5 V 60 h 6 6 v -8 l -3,-2 -3,2 v 8 H 25 V 37 l -2,-2 v -7 l 1,-1 h 3 l 1,1 v 4 h 3 v -4 l 1,-1 h 4 l 1,1 v 4 h 3 v -4 l 1,-1 h 3 l 1,1 v 7 l -2,2 v 58 z"
|
|
||||||
id="path1-7-5"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="display:inline;fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 97,95 V 75 L 95,70 V 60 h -6 -6 v -8 l 3,-2 3,2 v 8 h 6 V 37 l 2,-2 v -7 l -1,-1 h -3 l -1,1 v 4 h -3 v -4 l -1,-1 h -4 l -1,1 v 4 h -3 v -4 l -1,-1 h -3 l -1,1 v 7 l 2,2 v 58 z"
|
|
||||||
id="path1-7-5-8"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 46,95 V 37 l 2,-2 v -7 l -3,-3 v -7 l 1,-1 h 3 l 1,1 v 4 h 5 v -4 l 1,-1 h 8 l 1,1 v 4 h 5 v -4 l 1,-1 h 3 l 1,1 v 7 l -3,3 v 7 l 2,2 v 58 z m 19,0 V 70 l -1,-2 -2,-2 -2,-1 -2,1 -2,2 -1,2 v 25 z"
|
|
||||||
id="path5"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccc" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.8 KiB |
@ -1,85 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="dragon_dusk.svg"
|
|
||||||
inkscape:export-filename="dragon_dusk.png"
|
|
||||||
inkscape:export-xdpi="96"
|
|
||||||
inkscape:export-ydpi="96"
|
|
||||||
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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="9.8416665"
|
|
||||||
inkscape:cx="33.480102"
|
|
||||||
inkscape:cy="60.762067"
|
|
||||||
inkscape:window-width="2584"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1261"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707107"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 45,100 5,-10 1,-15 -1,-5 -3,5 -1,5 v 10 l -5,-10 -1,-10 3,-15 2,-5 7,-20 5,-5 1,-1 1,-3 -1,-3 -3,-5 v -2 l 2,1 3,4 3,-4 2,-1 v 2 l -3,5 -1,3 1,3 1,1 5,5 7,20 2,5 3,15 -1,10 -5,10 V 80 l -1,-5 -3,-5 -1,5 1,15 5,10 z"
|
|
||||||
id="path1"
|
|
||||||
sodipodi:nodetypes="cccccccccccccccccccccccccccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 41,90 -5,-10 -1,-10 3,-15 2,-5 5,-10 -1,-3 -4,-8 -5,-1 3,3 1,3 -1,3 -15,-2 -10,3 -3,10 1,7 1,13 3,10 3,6 5,7 7,4 -3,-5 V 85 L 23,75 V 65 l 2,-10 8,-7 -3,7 -3,10 -1,10 4,10 5,15 h 5 l 3,-6 z"
|
|
||||||
id="path2"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 79,90 5,-10 1,-10 -3,-15 -2,-5 -5,-10 1,-3 4,-8 5,-1 -3,3 -1,3 1,3 15,-2 10,3 3,10 -1,7 -1,13 -3,10 -3,6 -5,7 -7,4 3,-5 V 85 L 97,75 V 65 l -2,-10 -8,-7 3,7 3,10 1,10 -4,10 -5,15 h -5 l -3,-6 z"
|
|
||||||
id="path2-0"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccc" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.9 KiB |
@ -1,90 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="king_dusk.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="6.9591092"
|
|
||||||
inkscape:cx="67.609228"
|
|
||||||
inkscape:cy="61.214731"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707107"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 35,75 30,55 h 5 l 5,10 h 5 L 40,50 h 5 l 5,10 h 20 l 5,-10 h 5 l -5,15 h 5 l 5,-10 h 5 l -5,20 h -5 l -5,-5 h -5 l -5,5 H 55 l -5,-5 h -5 l -5,5 z"
|
|
||||||
id="path11"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 35,80 h 5 l 5,-5 h 5 l 5,5 h 10 l 5,-5 h 5 l 5,5 h 5 v 15 l -5,5 H 40 l -5,-5 z"
|
|
||||||
id="path12"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 50,40 60,50 70,40 75,30 V 25 L 60,15 45,25 v 5 z"
|
|
||||||
id="path13"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 35,35 -5,5 5,5 5,-5 z"
|
|
||||||
id="path1" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 85,35 -5,5 5,5 5,-5 z"
|
|
||||||
id="path1-6" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.6 KiB |
@ -1,72 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="knight_dusk.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="9.8416665"
|
|
||||||
inkscape:cx="63.759527"
|
|
||||||
inkscape:cy="60.355632"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707108"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 40,90 5,-25 v -5 l -5,5 -5,10 5,5 -5,5 -5,-10 5,-15 2,-5 2,-4 -4,-1 h -5 l -5,5 -10,-5 v -5 l 2,-4 -1,-6 v -4 l 2,4 2,3 5,-8 v -5 l 5,5 5,-5 5,5 15,5 h 30 l 10,5 5,14 2,9 -2,-1 -1,-2 -1,5 -3,8 v 7 l -1,10 h -6 l 1,-10 -1,-6 -4,-5 -3,11 -3,10 h -5 l 1,-2 2,-8 V 75 L 73,69 67,65 H 55 l -5,5 -5,20 z"
|
|
||||||
id="path4"
|
|
||||||
sodipodi:nodetypes="ccccccccccccccccccccccccccccccccccccccccccccccccccccc" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.2 KiB |
@ -1,82 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="lance_dusk.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="19.683333"
|
|
||||||
inkscape:cx="54.741745"
|
|
||||||
inkscape:cy="73.717189"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707108"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 55,100 H 65 V 90 l -5,5 -5,-5 z"
|
|
||||||
id="path13"
|
|
||||||
sodipodi:nodetypes="cccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 75,90 85,85 90,75 H 70 l -5,5 H 55 L 50,75 H 30 l 5,10 10,5 10,-5 5,5 5,-5 z"
|
|
||||||
id="path14"
|
|
||||||
sodipodi:nodetypes="cccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 55,70 v 5 l 2,2 h 6 l 2,-2 V 70 L 70,65 65,30 60,10 55,30 50,65 Z"
|
|
||||||
id="path15"
|
|
||||||
sodipodi:nodetypes="cccccccccccc" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.3 KiB |
@ -1,72 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="militia_dusk.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="9.8416666"
|
|
||||||
inkscape:cx="61.930568"
|
|
||||||
inkscape:cy="56.088061"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 35,87 V 47 37 l 10,-10 10,-5 5,-5 5,5 10,5 10,10 V 47 87 H 77 V 52 l -5,-5 -6,2 -2,3 v 15 l -1,5 H 57 L 56,67 V 52 l -2,-3 -6,-2 -5,5 v 35 z"
|
|
||||||
id="path10"
|
|
||||||
sodipodi:nodetypes="cccccccccccccccccccccccccc" />
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707107"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 916 B |
Before Width: | Height: | Size: 932 B |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 886 B |
Before Width: | Height: | Size: 911 B |
Before Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 2.4 KiB |
@ -1,111 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
|
||||||
|
|
||||||
<svg
|
|
||||||
width="120"
|
|
||||||
height="120"
|
|
||||||
viewBox="0 0 120 120"
|
|
||||||
version="1.1"
|
|
||||||
id="svg1"
|
|
||||||
inkscape:version="1.3.2 (091e20e, 2023-11-25, custom)"
|
|
||||||
sodipodi:docname="tower_dusk_v0.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"
|
|
||||||
xmlns:svg="http://www.w3.org/2000/svg">
|
|
||||||
<sodipodi:namedview
|
|
||||||
id="namedview1"
|
|
||||||
pagecolor="#ffffff"
|
|
||||||
bordercolor="#111111"
|
|
||||||
borderopacity="1"
|
|
||||||
inkscape:showpageshadow="0"
|
|
||||||
inkscape:pageopacity="0"
|
|
||||||
inkscape:pagecheckerboard="1"
|
|
||||||
inkscape:deskcolor="#d1d1d1"
|
|
||||||
inkscape:document-units="px"
|
|
||||||
showgrid="true"
|
|
||||||
inkscape:zoom="6.9591092"
|
|
||||||
inkscape:cx="35.708593"
|
|
||||||
inkscape:cy="58.628193"
|
|
||||||
inkscape:window-width="2588"
|
|
||||||
inkscape:window-height="1368"
|
|
||||||
inkscape:window-x="1257"
|
|
||||||
inkscape:window-y="0"
|
|
||||||
inkscape:window-maximized="0"
|
|
||||||
inkscape:current-layer="layer1">
|
|
||||||
<inkscape:grid
|
|
||||||
id="grid1"
|
|
||||||
units="px"
|
|
||||||
originx="0"
|
|
||||||
originy="0"
|
|
||||||
spacingx="1"
|
|
||||||
spacingy="1"
|
|
||||||
empcolor="#0099e5"
|
|
||||||
empopacity="0.30196078"
|
|
||||||
color="#0099e5"
|
|
||||||
opacity="0.14901961"
|
|
||||||
empspacing="5"
|
|
||||||
dotted="false"
|
|
||||||
gridanglex="30"
|
|
||||||
gridanglez="30"
|
|
||||||
visible="true" />
|
|
||||||
</sodipodi:namedview>
|
|
||||||
<defs
|
|
||||||
id="defs1" />
|
|
||||||
<g
|
|
||||||
inkscape:label="Layer 1"
|
|
||||||
inkscape:groupmode="layer"
|
|
||||||
id="layer1">
|
|
||||||
<rect
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1;stroke-width:0.707107"
|
|
||||||
id="rect2-4-8-6"
|
|
||||||
width="60"
|
|
||||||
height="5"
|
|
||||||
x="30"
|
|
||||||
y="105" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 40,50 35,95 H 85 L 80,50 h -5 l 5,40 H 40 l 5,-40 z"
|
|
||||||
id="path3"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 44,58 36,32 h 3 V 87 L 47,55 h -3 z"
|
|
||||||
id="path4"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 73,55 37,87 v 3 h 3 L 76,58 v -3 z"
|
|
||||||
id="path5"
|
|
||||||
sodipodi:nodetypes="ccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 35,50 1,-25 h 3 L 38,45 H 82 L 81,25 h 3 l 1,25 z"
|
|
||||||
id="path6"
|
|
||||||
sodipodi:nodetypes="ccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 35,25 H 30 V 20 L 45,10 h 30 l 15,10 v 5 H 75 l -5,-5 -5,5 H 55 l -5,-5 -5,5 z"
|
|
||||||
id="path9"
|
|
||||||
sodipodi:nodetypes="cccccccccccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="M 42,32 41,42 H 79 L 78,32 Z"
|
|
||||||
id="path13"
|
|
||||||
sodipodi:nodetypes="ccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 35,95 -1,5 h 6 v -5 z"
|
|
||||||
id="path14"
|
|
||||||
sodipodi:nodetypes="ccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 85,95 1,5 h -6 v -5 z"
|
|
||||||
id="path14-3"
|
|
||||||
sodipodi:nodetypes="ccccc" />
|
|
||||||
<path
|
|
||||||
style="fill:#f6a1bd;fill-opacity:1"
|
|
||||||
d="m 44,53 -1,5 h 34 l -1,-5 z"
|
|
||||||
id="path15" />
|
|
||||||
</g>
|
|
||||||
</svg>
|
|
Before Width: | Height: | Size: 3.1 KiB |
@ -46,7 +46,7 @@ const OpCode = {
|
|||||||
SessionLeave :0x002F,
|
SessionLeave :0x002F,
|
||||||
|
|
||||||
GameState :0x0030,
|
GameState :0x0030,
|
||||||
GamePlay :0x0031,
|
GameMessage :0x0031,
|
||||||
GameHistory :0x0032,
|
GameHistory :0x0032,
|
||||||
|
|
||||||
Challenge :0x0060,
|
Challenge :0x0060,
|
||||||
@ -61,3 +61,17 @@ const GameState = {
|
|||||||
Ongoing :0x01,
|
Ongoing :0x01,
|
||||||
Complete :0x02,
|
Complete :0x02,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const GameMessage = {
|
||||||
|
Error :0x00,
|
||||||
|
|
||||||
|
Move :0x01,
|
||||||
|
Drop :0x02,
|
||||||
|
Alt :0x03,
|
||||||
|
|
||||||
|
Online :0x08,
|
||||||
|
Undo :0x10,
|
||||||
|
Retire :0x11,
|
||||||
|
|
||||||
|
Reaction :0x20,
|
||||||
|
};
|
||||||
|
@ -246,7 +246,6 @@ GAME.Game = class {
|
|||||||
this.state = {
|
this.state = {
|
||||||
code:0,
|
code:0,
|
||||||
check:false,
|
check:false,
|
||||||
checkmate:false,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.update_board();
|
this.update_board();
|
||||||
@ -335,7 +334,9 @@ GAME.Game = class {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(moves == 0) { this.state.checkmate = true; }
|
console.log(moves);
|
||||||
|
|
||||||
|
if(moves == 0) { this.state.code = GAME.Const.State.Checkmate; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -347,7 +348,7 @@ GAME.Game = class {
|
|||||||
// Move piece on board.
|
// Move piece on board.
|
||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
case 0:
|
case 0:
|
||||||
case 3: {
|
case 2: {
|
||||||
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;
|
||||||
@ -389,7 +390,7 @@ GAME.Game = class {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle alt moves.
|
// Handle alt moves.
|
||||||
if(play.source == 3) {
|
if(play.source == 2) {
|
||||||
switch(moves.alt) {
|
switch(moves.alt) {
|
||||||
case 1: {
|
case 1: {
|
||||||
piece.promoted = false;
|
piece.promoted = false;
|
||||||
@ -410,11 +411,6 @@ GAME.Game = class {
|
|||||||
this.pools[this.turn & 1].pieces[play.from] -= 1;
|
this.pools[this.turn & 1].pieces[play.from] -= 1;
|
||||||
this.turn++;
|
this.turn++;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// Play retired.
|
|
||||||
case 2: {
|
|
||||||
this.state.code = 2;
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recalculate new board state.
|
// Recalculate new board state.
|
||||||
@ -784,9 +780,9 @@ GAME.Const = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
State: {
|
State: {
|
||||||
Ongoing: 0,
|
Current: 0,
|
||||||
Complete: 1,
|
Checkmate: 1,
|
||||||
Resign: 2,
|
Resign: 2,
|
||||||
},
|
},
|
||||||
|
|
||||||
Direction: [
|
Direction: [
|
||||||
|
@ -1,21 +1,64 @@
|
|||||||
const GAME_ASSET = { };
|
const GAME_EMOJI = [
|
||||||
|
"Promote",
|
||||||
|
"Militia",
|
||||||
|
"Lance",
|
||||||
|
"Knight",
|
||||||
|
"Tower",
|
||||||
|
"Castle",
|
||||||
|
"Dragon",
|
||||||
|
"Behemoth",
|
||||||
|
"Heart",
|
||||||
|
];
|
||||||
|
const GAME_EMOJI_COLOR = [
|
||||||
|
"Promote",
|
||||||
|
"Dawn",
|
||||||
|
"Dusk",
|
||||||
|
];
|
||||||
|
|
||||||
GAME_ASSET.load_image = (image) => {
|
class GameImage {
|
||||||
let img = new Image();
|
constructor(paths=[]) {
|
||||||
img.src = image;
|
this.paths = paths;
|
||||||
return img;
|
}
|
||||||
};
|
|
||||||
|
|
||||||
GAME_ASSET.Image = {
|
draw(ctx, scale=1., offset=[0, 0], color=null) {
|
||||||
Promote: GAME_ASSET.load_image("/asset/promote.svg"),
|
for(let path of this.paths) {
|
||||||
Piece: [
|
if(color === null) {
|
||||||
[ GAME_ASSET.load_image("/asset/militia_dawn.svg"), GAME_ASSET.load_image("/asset/militia_dusk.svg") ],
|
ctx.fillStyle = path[0];
|
||||||
[ GAME_ASSET.load_image("/asset/lance_dawn.svg"), GAME_ASSET.load_image("/asset/lance_dusk.svg") ],
|
} else {
|
||||||
[ GAME_ASSET.load_image("/asset/knight_dawn.svg"), GAME_ASSET.load_image("/asset/knight_dusk.svg") ],
|
ctx.fillStyle = color;
|
||||||
[ GAME_ASSET.load_image("/asset/tower_dawn.svg"), GAME_ASSET.load_image("/asset/tower_dusk.svg") ],
|
}
|
||||||
[ 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") ],
|
let origin = [0, 0];
|
||||||
[ GAME_ASSET.load_image("/asset/behemoth_dawn.svg"), GAME_ASSET.load_image("/asset/behemoth_dusk.svg") ],
|
|
||||||
[ GAME_ASSET.load_image("/asset/heart_dawn.svg"), GAME_ASSET.load_image("/asset/heart_dusk.svg") ],
|
ctx.beginPath();
|
||||||
],
|
for(let segment of path[1]) {
|
||||||
};
|
switch(segment[0]) {
|
||||||
|
case 0: {
|
||||||
|
origin = segment[1];
|
||||||
|
ctx.moveTo(
|
||||||
|
(scale * segment[1][0]) + offset[0],
|
||||||
|
(scale * segment[1][1]) + offset[1],
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case 1: {
|
||||||
|
ctx.lineTo(
|
||||||
|
(scale * segment[1][0]) + offset[0],
|
||||||
|
(scale * segment[1][1]) + offset[1],
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
case 2: {
|
||||||
|
|
||||||
|
} break;
|
||||||
|
case 3: {
|
||||||
|
ctx.lineTo(
|
||||||
|
(scale * origin[0]) + offset[0],
|
||||||
|
(scale * origin[1]) + offset[1],
|
||||||
|
);
|
||||||
|
} break;
|
||||||
|
default: console.log(segment.mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,6 +18,8 @@ const INTERFACE = {
|
|||||||
TileMedium: "#242424",
|
TileMedium: "#242424",
|
||||||
TileDark: "#101010",
|
TileDark: "#101010",
|
||||||
|
|
||||||
|
Promote: "#a52121",
|
||||||
|
|
||||||
Dawn: "#ffe082",
|
Dawn: "#ffe082",
|
||||||
DawnMedium: "#fca03f",
|
DawnMedium: "#fca03f",
|
||||||
DawnDark: "#ff6d00",
|
DawnDark: "#ff6d00",
|
||||||
@ -60,8 +62,8 @@ const INTERFACE = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
resolve_board() {
|
resolve_board() {
|
||||||
for(let i = 0; i < INTERFACE_DATA.board_state.length; ++i) {
|
for(let i = 0; i < INTERFACE_DATA.Game.board_state.length; ++i) {
|
||||||
INTERFACE_DATA.board_state[i] = [0, 0];
|
INTERFACE_DATA.Game.board_state[i] = [0, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(INTERFACE_DATA.select !== null) { INTERFACE.resolve_piece(INTERFACE_DATA.select, 1); }
|
if(INTERFACE_DATA.select !== null) { INTERFACE.resolve_piece(INTERFACE_DATA.select, 1); }
|
||||||
@ -103,18 +105,18 @@ const INTERFACE = {
|
|||||||
if(movement.valid) {
|
if(movement.valid) {
|
||||||
// Show valid/threat hints if piece belongs to player and is player turn.
|
// Show valid/threat hints if piece belongs to player and is player turn.
|
||||||
if(INTERFACE_DATA.player == 2 || player == INTERFACE_DATA.player) {
|
if(INTERFACE_DATA.player == 2 || player == INTERFACE_DATA.player) {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Valid;
|
INTERFACE_DATA.Game.board_state[movement.tile][zone] = INTERFACE.TileStatus.Valid;
|
||||||
/*if(GAME_DATA.board.tiles[movement.tile].threaten[+(!player)] > 0) {
|
/*if(GAME_DATA.board.tiles[movement.tile].threaten[+(!player)] > 0) {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Threat;
|
INTERFACE_DATA.Game.board_state[movement.tile][zone] = INTERFACE.TileStatus.Threat;
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Valid;
|
INTERFACE_DATA.Game.board_state[movement.tile][zone] = INTERFACE.TileStatus.Valid;
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Opponent;
|
INTERFACE_DATA.Game.board_state[movement.tile][zone] = INTERFACE.TileStatus.Opponent;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.board_state[movement.tile][zone] = INTERFACE.TileStatus.Invalid;
|
INTERFACE_DATA.Game.board_state[movement.tile][zone] = INTERFACE.TileStatus.Invalid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -123,7 +125,7 @@ const INTERFACE = {
|
|||||||
hover(event) {
|
hover(event) {
|
||||||
let initial_hover = INTERFACE_DATA.hover;
|
let initial_hover = INTERFACE_DATA.hover;
|
||||||
|
|
||||||
let apothem = INTERFACE_DATA.Ui.scale;
|
let apothem = INTERFACE_DATA.Render.scale;
|
||||||
let radius = INTERFACE.Radius * apothem;
|
let radius = INTERFACE.Radius * apothem;
|
||||||
let halfradius = radius / 2;
|
let halfradius = radius / 2;
|
||||||
let grid_offset_x = 1.5 * radius;
|
let grid_offset_x = 1.5 * radius;
|
||||||
@ -133,11 +135,11 @@ const INTERFACE = {
|
|||||||
INTERFACE_DATA.hover = null;
|
INTERFACE_DATA.hover = null;
|
||||||
|
|
||||||
// Handle board area
|
// Handle board area
|
||||||
if(event.offsetY >= INTERFACE_DATA.Ui.margin.t && event.offsetY < INTERFACE_DATA.Ui.margin.l + INTERFACE_DATA.Ui.area.y) {
|
if(event.offsetY >= INTERFACE_DATA.Render.margin.t && event.offsetY < INTERFACE_DATA.Render.margin.l + INTERFACE_DATA.Render.area.y) {
|
||||||
if(event.offsetX >= INTERFACE_DATA.Ui.offset.x && event.offsetX < INTERFACE_DATA.Ui.offset.x + INTERFACE_DATA.Ui.board_width) {
|
if(event.offsetX >= INTERFACE_DATA.Render.offset.x && event.offsetX < INTERFACE_DATA.Render.offset.x + INTERFACE_DATA.Render.board_width) {
|
||||||
|
|
||||||
let basis_x = INTERFACE_DATA.Ui.offset.x + halfradius;
|
let basis_x = INTERFACE_DATA.Render.offset.x + halfradius;
|
||||||
let basis_y = INTERFACE_DATA.Ui.offset.y + (14 * apothem);
|
let basis_y = INTERFACE_DATA.Render.offset.y + (14 * apothem);
|
||||||
|
|
||||||
let x = (event.offsetX - basis_x) / grid_offset_x;
|
let x = (event.offsetX - basis_x) / grid_offset_x;
|
||||||
let y = -(event.offsetY - basis_y) / apothem;
|
let y = -(event.offsetY - basis_y) / apothem;
|
||||||
@ -165,10 +167,10 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle pool area
|
// Handle pool area
|
||||||
else if(event.offsetX >= INTERFACE_DATA.Ui.pool_offset && event.offsetX < INTERFACE_DATA.Ui.offset.x + INTERFACE_DATA.Ui.area.x) {
|
else if(event.offsetX >= INTERFACE_DATA.Render.pool_offset && event.offsetX < INTERFACE_DATA.Render.offset.x + INTERFACE_DATA.Render.area.x) {
|
||||||
|
|
||||||
let basis_x = INTERFACE_DATA.Ui.pool_offset + halfradius;
|
let basis_x = INTERFACE_DATA.Render.pool_offset + halfradius;
|
||||||
let basis_y = INTERFACE_DATA.Ui.offset.y + (3 * apothem);
|
let basis_y = INTERFACE_DATA.Render.offset.y + (3 * apothem);
|
||||||
|
|
||||||
let x = (event.offsetX - basis_x) / grid_offset_x;
|
let x = (event.offsetX - basis_x) / grid_offset_x;
|
||||||
let y = (event.offsetY - basis_y) / apothem;
|
let y = (event.offsetY - basis_y) / apothem;
|
||||||
@ -198,13 +200,13 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(initial_hover != INTERFACE_DATA.hover) { INTERFACE.draw(); }
|
if(initial_hover != INTERFACE_DATA.hover) { INTERFACE.step(); }
|
||||||
},
|
},
|
||||||
|
|
||||||
unhover() {
|
unhover() {
|
||||||
let redraw = (INTERFACE_DATA.hover !== null);
|
let redraw = (INTERFACE_DATA.hover !== null);
|
||||||
INTERFACE_DATA.hover = null;
|
INTERFACE_DATA.hover = null;
|
||||||
if(redraw) { INTERFACE.draw(); }
|
if(redraw) { INTERFACE.step(); }
|
||||||
},
|
},
|
||||||
|
|
||||||
click(event) {
|
click(event) {
|
||||||
@ -228,8 +230,20 @@ const INTERFACE = {
|
|||||||
|
|
||||||
// Play selection.
|
// Play selection.
|
||||||
if(INTERFACE_DATA.hover.source == 0 && (INTERFACE_DATA.mode == INTERFACE.Mode.Local || INTERFACE_DATA.player == (GAME_DATA.turn & 1))) {
|
if(INTERFACE_DATA.hover.source == 0 && (INTERFACE_DATA.mode == INTERFACE.Mode.Local || INTERFACE_DATA.player == (GAME_DATA.turn & 1))) {
|
||||||
let tile_state = INTERFACE_DATA.board_state[INTERFACE_DATA.hover.tile][1];
|
let tile_state = INTERFACE_DATA.Game.board_state[INTERFACE_DATA.hover.tile][1];
|
||||||
result = +(tile_state == INTERFACE.TileStatus.Valid || tile_state == INTERFACE.TileStatus.Threat);
|
result = +(tile_state == INTERFACE.TileStatus.Valid || tile_state == INTERFACE.TileStatus.Threat);
|
||||||
|
if(INTERFACE_DATA.select.source == 1) {
|
||||||
|
let pool_selected = +(INTERFACE_DATA.select.tile >= 7);
|
||||||
|
|
||||||
|
pool_selected ^= (INTERFACE_DATA.player & 1);
|
||||||
|
if(INTERFACE_DATA.mode == INTERFACE.Mode.Local) {
|
||||||
|
pool_selected ^= INTERFACE_DATA.rotate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((GAME_DATA.turn & 1) != pool_selected) {
|
||||||
|
result = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Alt move selection.
|
// Alt move selection.
|
||||||
@ -254,7 +268,7 @@ const INTERFACE = {
|
|||||||
console.log("D1");
|
console.log("D1");
|
||||||
let source = INTERFACE_DATA.select.source;
|
let source = INTERFACE_DATA.select.source;
|
||||||
if(source == 0 && INTERFACE_DATA.alt_mode) {
|
if(source == 0 && INTERFACE_DATA.alt_mode) {
|
||||||
source = 3;
|
source = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
let play = new GAME.Play(
|
let play = new GAME.Play(
|
||||||
@ -270,7 +284,7 @@ const INTERFACE = {
|
|||||||
|
|
||||||
case 0: {
|
case 0: {
|
||||||
console.log("D2");
|
console.log("D2");
|
||||||
// Handle new selection.
|
// Handle new selection.
|
||||||
INTERFACE_DATA.select = null;
|
INTERFACE_DATA.select = null;
|
||||||
INTERFACE_DATA.alt_mode = false;
|
INTERFACE_DATA.alt_mode = false;
|
||||||
|
|
||||||
@ -310,7 +324,7 @@ const INTERFACE = {
|
|||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
},
|
},
|
||||||
|
|
||||||
contextmenu() {
|
contextmenu() {
|
||||||
@ -325,7 +339,7 @@ const INTERFACE = {
|
|||||||
if(INTERFACE.Ui.match_select(INTERFACE_DATA.hover, INTERFACE_DATA.select)) {
|
if(INTERFACE.Ui.match_select(INTERFACE_DATA.hover, INTERFACE_DATA.select)) {
|
||||||
INTERFACE_DATA.select = null;
|
INTERFACE_DATA.select = null;
|
||||||
INTERFACE_DATA.alt_mode = false;
|
INTERFACE_DATA.alt_mode = false;
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
} else {
|
} else {
|
||||||
INTERFACE.click({button:0});
|
INTERFACE.click({button:0});
|
||||||
}
|
}
|
||||||
@ -337,11 +351,11 @@ const INTERFACE = {
|
|||||||
let width = INTERFACE_DATA.canvas.width = INTERFACE_DATA.canvas.clientWidth;
|
let width = INTERFACE_DATA.canvas.width = INTERFACE_DATA.canvas.clientWidth;
|
||||||
let height = INTERFACE_DATA.canvas.height = INTERFACE_DATA.canvas.clientHeight;
|
let height = INTERFACE_DATA.canvas.height = INTERFACE_DATA.canvas.clientHeight;
|
||||||
|
|
||||||
INTERFACE_DATA.Ui.margin.t = Math.floor(Math.min(width, height) / 96);
|
INTERFACE_DATA.Render.margin.t = Math.floor(Math.min(width, height) / 96);
|
||||||
INTERFACE_DATA.Ui.margin.l = 1.75 * INTERFACE_DATA.Ui.margin.t;
|
INTERFACE_DATA.Render.margin.l = 1.75 * INTERFACE_DATA.Render.margin.t;
|
||||||
INTERFACE_DATA.Ui.margin.r = INTERFACE_DATA.Ui.margin.t;
|
INTERFACE_DATA.Render.margin.r = INTERFACE_DATA.Render.margin.t;
|
||||||
INTERFACE_DATA.Ui.margin.b = 3 * INTERFACE_DATA.Ui.margin.t;
|
INTERFACE_DATA.Render.margin.b = 3 * INTERFACE_DATA.Render.margin.t;
|
||||||
let margin = INTERFACE_DATA.Ui.margin;
|
let margin = INTERFACE_DATA.Render.margin;
|
||||||
|
|
||||||
let gui_width = width - (margin.l + margin.r);
|
let gui_width = width - (margin.l + margin.r);
|
||||||
let gui_height = height - (margin.t + margin.b);
|
let gui_height = height - (margin.t + margin.b);
|
||||||
@ -354,40 +368,43 @@ const INTERFACE = {
|
|||||||
|
|
||||||
let gui_scale = gui_height * INTERFACE.Scale;
|
let gui_scale = gui_height * INTERFACE.Scale;
|
||||||
|
|
||||||
INTERFACE_DATA.Ui.area.x = gui_width;
|
INTERFACE_DATA.Render.area.x = gui_width;
|
||||||
INTERFACE_DATA.Ui.area.y = gui_height;
|
INTERFACE_DATA.Render.area.y = gui_height;
|
||||||
INTERFACE_DATA.Ui.scale = gui_scale;
|
INTERFACE_DATA.Render.scale = gui_scale;
|
||||||
|
|
||||||
INTERFACE_DATA.Ui.offset.x = (INTERFACE_DATA.Ui.margin.l - INTERFACE_DATA.Ui.margin.r) + (width - gui_width) / 2;
|
INTERFACE_DATA.Render.offset.x = (INTERFACE_DATA.Render.margin.l - INTERFACE_DATA.Render.margin.r) + (width - gui_width) / 2;
|
||||||
INTERFACE_DATA.Ui.offset.y = (INTERFACE_DATA.Ui.margin.t - INTERFACE_DATA.Ui.margin.b) + (height - gui_height) / 2;
|
INTERFACE_DATA.Render.offset.y = (INTERFACE_DATA.Render.margin.t - INTERFACE_DATA.Render.margin.b) + (height - gui_height) / 2;
|
||||||
|
|
||||||
INTERFACE_DATA.Ui.board_width = Math.ceil(INTERFACE.BoardWidth * gui_scale);
|
INTERFACE_DATA.Render.board_width = Math.ceil(INTERFACE.BoardWidth * gui_scale);
|
||||||
INTERFACE_DATA.Ui.pool_offset = INTERFACE_DATA.Ui.offset.x + Math.floor(INTERFACE.PoolOffset * gui_scale);
|
INTERFACE_DATA.Render.pool_offset = INTERFACE_DATA.Render.offset.x + Math.floor(INTERFACE.PoolOffset * gui_scale);
|
||||||
|
},
|
||||||
|
|
||||||
|
step() {
|
||||||
|
if(INTERFACE_DATA === null) return;
|
||||||
|
|
||||||
|
INTERFACE.resolve_board();
|
||||||
|
|
||||||
|
if(INTERFACE_DATA.Timeout.draw === null) {
|
||||||
|
INTERFACE.draw();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
draw() {
|
draw() {
|
||||||
if(INTERFACE_DATA === null) return;
|
|
||||||
|
|
||||||
INTERFACE.resize();
|
INTERFACE.resize();
|
||||||
INTERFACE.resolve_board();
|
|
||||||
|
|
||||||
INTERFACE.render();
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
let canvas = INTERFACE_DATA.canvas;
|
let canvas = INTERFACE_DATA.canvas;
|
||||||
let ctx = INTERFACE_DATA.context;
|
let ctx = INTERFACE_DATA.context;
|
||||||
|
|
||||||
let width = canvas.width;
|
let width = canvas.width;
|
||||||
let height = canvas.height;
|
let height = canvas.height;
|
||||||
|
|
||||||
let gui_margin = INTERFACE_DATA.Ui.margin;
|
let gui_margin = INTERFACE_DATA.Render.margin;
|
||||||
let gui_offset = INTERFACE_DATA.Ui.offset;
|
let gui_offset = INTERFACE_DATA.Render.offset;
|
||||||
let gui_scale = INTERFACE_DATA.Ui.scale;
|
let gui_scale = INTERFACE_DATA.Render.scale;
|
||||||
|
|
||||||
let play = null;
|
let play = null;
|
||||||
if(INTERFACE_DATA.replay_turn > 0) {
|
if(INTERFACE_DATA.Replay.turn > 0) {
|
||||||
play = INTERFACE_DATA.history[INTERFACE_DATA.replay_turn - 1];
|
play = INTERFACE_DATA.Game.history[INTERFACE_DATA.Replay.turn - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -397,11 +414,49 @@ const INTERFACE = {
|
|||||||
ctx.fillRect(0, 0, width, height);
|
ctx.fillRect(0, 0, width, height);
|
||||||
|
|
||||||
|
|
||||||
|
// Draw particles
|
||||||
|
for(let p = 0; p < INTERFACE_DATA.Animation.particles.length; ++p) {
|
||||||
|
let particle = INTERFACE_DATA.Animation.particles[p];
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
if(particle !== null) {
|
||||||
|
if(particle.time > 0) {
|
||||||
|
let name = GAME_EMOJI[particle.index];
|
||||||
|
let color = INTERFACE.Color[GAME_EMOJI_COLOR[particle.color]];
|
||||||
|
|
||||||
|
ctx.translate((width / 10) + particle.position[0], height - particle.position[1]);
|
||||||
|
ctx.rotate(particle.rotation);
|
||||||
|
|
||||||
|
if(particle.time < 1) {
|
||||||
|
ctx.globalAlpha = Math.max(0, particle.time);
|
||||||
|
}
|
||||||
|
|
||||||
|
GAME_ASSET.Image[name].draw(ctx, particle.scale * gui_scale, [0, 0], color);
|
||||||
|
|
||||||
|
particle.position[0] += particle.velocity[0];
|
||||||
|
particle.position[1] += particle.velocity[1];
|
||||||
|
particle.rotation += particle.angular;
|
||||||
|
|
||||||
|
particle.time -= 30. / 1000;
|
||||||
|
} else {
|
||||||
|
INTERFACE_DATA.Animation.particles[p] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
let temp = INTERFACE_DATA.Animation.particles;
|
||||||
|
INTERFACE_DATA.Animation.particles = [ ];
|
||||||
|
for(particle of temp) {
|
||||||
|
if(particle !== null) {
|
||||||
|
INTERFACE_DATA.Animation.particles.push(particle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Draw tiles
|
// Draw tiles
|
||||||
let radius = INTERFACE.Radius * gui_scale;
|
let radius = INTERFACE.Radius * gui_scale;
|
||||||
let basis_x = gui_offset.x + radius;
|
let basis_x = gui_offset.x + radius;
|
||||||
let basis_y = gui_offset.y + (13 * gui_scale);
|
let basis_y = gui_offset.y + (13 * gui_scale);
|
||||||
let icon_radius = 0.69 * radius;
|
|
||||||
|
|
||||||
ctx.lineWidth = Math.min(gui_scale * 0.06, 3);
|
ctx.lineWidth = Math.min(gui_scale * 0.06, 3);
|
||||||
|
|
||||||
@ -413,13 +468,13 @@ const INTERFACE = {
|
|||||||
let is_hover = INTERFACE.Ui.tile_is_hover(0, i);
|
let is_hover = INTERFACE.Ui.tile_is_hover(0, i);
|
||||||
let is_select = INTERFACE.Ui.tile_is_select(0, i);
|
let is_select = INTERFACE.Ui.tile_is_select(0, i);
|
||||||
|
|
||||||
let tile_state = INTERFACE_DATA.board_state[i][1];
|
let tile_state = INTERFACE_DATA.Game.board_state[i][1];
|
||||||
let hover_state = INTERFACE_DATA.board_state[i][0];
|
let hover_state = INTERFACE_DATA.Game.board_state[i][0];
|
||||||
|
|
||||||
let draw_piece = true;
|
let draw_piece = true;
|
||||||
if(INTERFACE_DATA.Animate.play !== null) {
|
if(INTERFACE_DATA.Animation.piece !== null) {
|
||||||
let play = INTERFACE_DATA.Animate.play;
|
let play = INTERFACE_DATA.Animation.piece.play;
|
||||||
draw_piece = draw_piece && !((play.source == 0 || play.source == 3) && (play.from == i || play.to == i));
|
draw_piece = draw_piece && !((play.source == 0 || play.source == 2) && (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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +494,7 @@ const INTERFACE = {
|
|||||||
if(tile.piece !== null) { piece = GAME_DATA.board.pieces[tile.piece]; }
|
if(tile.piece !== null) { piece = GAME_DATA.board.pieces[tile.piece]; }
|
||||||
|
|
||||||
let is_play = null;
|
let is_play = null;
|
||||||
if(GAME_DATA.turn > 0 && (play.source < 2 || play.source == 3) && (play.to == i || ((play.source == 0 || play.source == 3) && play.from == i))) {
|
if(GAME_DATA.turn > 0 && (play.to == i || ((play.source == 0 || play.source == 2) && play.from == i))) {
|
||||||
is_play = +!(GAME_DATA.turn & 1);
|
is_play = +!(GAME_DATA.turn & 1);
|
||||||
}
|
}
|
||||||
let is_check = GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Heart && piece.player == (GAME_DATA.turn & 1);
|
let is_check = GAME_DATA.state.check != 0 && piece !== null && piece.piece == GAME.Const.PieceId.Heart && piece.player == (GAME_DATA.turn & 1);
|
||||||
@ -520,16 +575,22 @@ const INTERFACE = {
|
|||||||
|
|
||||||
// Draw tile content
|
// Draw tile content
|
||||||
if(draw_piece && piece !== null) {
|
if(draw_piece && piece !== null) {
|
||||||
|
let piece_def = GAME.Const.Piece[piece.piece];
|
||||||
|
let piece_color = (piece.player == GAME.Const.Player.Dawn)? INTERFACE.Color.Dawn : INTERFACE.Color.Dusk;
|
||||||
|
|
||||||
// Draw border hints
|
// Draw border hints
|
||||||
if(!is_hover) { draw.hints(piece); }
|
if(!is_hover) { draw.hints(piece); }
|
||||||
|
|
||||||
// Draw piece icon
|
if(GAME_ASSET.Image[piece_def.name] !== undefined) {
|
||||||
if(INTERFACE_DATA.mirror && (piece.player ^ (INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate) != 0) {
|
// Draw piece icon
|
||||||
ctx.rotate(Math.PI);
|
if(INTERFACE_DATA.mirror && (piece.player ^ (INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate) != 0) {
|
||||||
|
ctx.rotate(Math.PI);
|
||||||
|
}
|
||||||
|
if(piece.promoted) {
|
||||||
|
GAME_ASSET.Image.Promote.draw(ctx, 1.5 * gui_scale, [0, 0], INTERFACE.Color.Promote);
|
||||||
|
}
|
||||||
|
GAME_ASSET.Image[piece_def.name].draw(ctx, 1.5 * gui_scale, [0, 0], piece_color);
|
||||||
}
|
}
|
||||||
if(piece.promoted) { ctx.drawImage(GAME_ASSET.Image.Promote, -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.); }
|
|
||||||
ctx.drawImage(GAME_ASSET.Image.Piece[piece.piece][piece.player], -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.restore();
|
ctx.restore();
|
||||||
@ -579,22 +640,22 @@ const INTERFACE = {
|
|||||||
// Player handles
|
// Player handles
|
||||||
ctx.font = Math.ceil(gui_scale / 1.3) + "px sans-serif";
|
ctx.font = Math.ceil(gui_scale / 1.3) + "px sans-serif";
|
||||||
|
|
||||||
if(INTERFACE_DATA.handles[0] !== null) {
|
if(INTERFACE_DATA.Session.Client.Dawn.handle !== null) {
|
||||||
let pos = handle_pos[(1 ^ INTERFACE_DATA.player ^ INTERFACE_DATA.rotate) & 1];
|
let pos = handle_pos[(1 ^ INTERFACE_DATA.player ^ INTERFACE_DATA.rotate) & 1];
|
||||||
|
|
||||||
ctx.fillStyle = INTERFACE.Color.Dawn;
|
ctx.fillStyle = INTERFACE.Color.Dawn;
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.fillText(INTERFACE_DATA.handles[0], pos.x, pos.y);
|
ctx.fillText(INTERFACE_DATA.Session.Client.Dawn.handle, pos.x, pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(INTERFACE_DATA.handles[1] !== null) {
|
if(INTERFACE_DATA.Session.Client.Dusk.handle !== null) {
|
||||||
let pos = handle_pos[(INTERFACE_DATA.player ^ INTERFACE_DATA.rotate) & 1];
|
let pos = handle_pos[(INTERFACE_DATA.player ^ INTERFACE_DATA.rotate) & 1];
|
||||||
|
|
||||||
ctx.fillStyle = INTERFACE.Color.Dusk;
|
ctx.fillStyle = INTERFACE.Color.Dusk;
|
||||||
ctx.textBaseline = "middle";
|
ctx.textBaseline = "middle";
|
||||||
ctx.textAlign = "center";
|
ctx.textAlign = "center";
|
||||||
ctx.fillText(INTERFACE_DATA.handles[1], pos.x, pos.y);
|
ctx.fillText(INTERFACE_DATA.Session.Client.Dusk.handle, pos.x, pos.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tile information
|
// Tile information
|
||||||
@ -630,8 +691,8 @@ const INTERFACE = {
|
|||||||
let message = null;
|
let message = null;
|
||||||
ctx.fillStyle = INTERFACE.Color.Text;
|
ctx.fillStyle = INTERFACE.Color.Text;
|
||||||
|
|
||||||
if(INTERFACE_DATA.auto_mode !== null) {
|
if(INTERFACE_DATA.Game.auto !== null) {
|
||||||
switch(INTERFACE_DATA.auto_mode) {
|
switch(INTERFACE_DATA.Game.auto) {
|
||||||
case 0: message = LANG("auto") + " " + LANG("dawn"); break;
|
case 0: message = LANG("auto") + " " + LANG("dawn"); break;
|
||||||
case 1: message = LANG("auto") + " " + LANG("dusk"); break;
|
case 1: message = LANG("auto") + " " + LANG("dusk"); break;
|
||||||
}
|
}
|
||||||
@ -642,7 +703,7 @@ const INTERFACE = {
|
|||||||
message = LANG("resign");
|
message = LANG("resign");
|
||||||
} else if(GAME_DATA.state.check != 0) {
|
} else if(GAME_DATA.state.check != 0) {
|
||||||
ctx.fillStyle = INTERFACE.Color.HintCheck;
|
ctx.fillStyle = INTERFACE.Color.HintCheck;
|
||||||
if(GAME_DATA.state.checkmate) {
|
if(GAME_DATA.state.code == GAME.Const.State.Checkmate) {
|
||||||
message = LANG("checkmate");
|
message = LANG("checkmate");
|
||||||
} else {
|
} else {
|
||||||
message = LANG("check");
|
message = LANG("check");
|
||||||
@ -703,13 +764,13 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if(INTERFACE_DATA.Animate.play !== null) {
|
if(INTERFACE_DATA.Animation.piece !== null) {
|
||||||
let time = Math.min(1 - (INTERFACE_DATA.Animate.time - Date.now()) / 1000, 1);
|
let time = Math.min(1 - (INTERFACE_DATA.Animation.piece.time - Date.now()) / 1000, 1);
|
||||||
time = time * time;
|
time = time * time;
|
||||||
let play = INTERFACE_DATA.Animate.play;
|
let play = INTERFACE_DATA.Animation.piece.play;
|
||||||
|
|
||||||
let piece = INTERFACE_DATA.Animate.piece;
|
let piece = INTERFACE_DATA.Animation.piece.piece;
|
||||||
let target = INTERFACE_DATA.Animate.target;
|
let target = INTERFACE_DATA.Animation.piece.target;
|
||||||
|
|
||||||
// Get to and from coordinates.
|
// Get to and from coordinates.
|
||||||
let coord_to = HEX.tile_to_hex(play.to);
|
let coord_to = HEX.tile_to_hex(play.to);
|
||||||
@ -725,7 +786,7 @@ const INTERFACE = {
|
|||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
// Lerp between board positions.
|
// Lerp between board positions.
|
||||||
case 0:
|
case 0:
|
||||||
case 3: {
|
case 2: {
|
||||||
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;
|
||||||
@ -744,7 +805,6 @@ const INTERFACE = {
|
|||||||
case 0: ctx.fillStyle = INTERFACE.Color.DawnMedium; break;
|
case 0: ctx.fillStyle = INTERFACE.Color.DawnMedium; break;
|
||||||
case 1: ctx.fillStyle = INTERFACE.Color.DuskMedium; break;
|
case 1: ctx.fillStyle = INTERFACE.Color.DuskMedium; break;
|
||||||
}
|
}
|
||||||
//ctx.fillStyle = INTERFACE.Color.AnimateShadow;
|
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.translate(to_x, to_y);
|
ctx.translate(to_x, to_y);
|
||||||
@ -773,12 +833,20 @@ const INTERFACE = {
|
|||||||
// Draw moving piece.
|
// Draw moving piece.
|
||||||
draw.animation_piece(piece, x, y);
|
draw.animation_piece(piece, x, y);
|
||||||
|
|
||||||
if(Date.now() >= INTERFACE_DATA.Animate.time) {
|
if(Date.now() >= INTERFACE_DATA.Animation.piece.time) {
|
||||||
INTERFACE_DATA.Animate.play = null;
|
INTERFACE_DATA.Animation.piece = null;
|
||||||
INTERFACE_DATA.Animate.time = 0;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(INTERFACE.render, 1000 / 30);
|
if(INTERFACE_DATA.Animation.piece !== null
|
||||||
|
|| INTERFACE_DATA.Animation.particles.length > 0)
|
||||||
|
{
|
||||||
|
INTERFACE_DATA.Timeout.draw = setTimeout(INTERFACE.draw, 1000 / 30);
|
||||||
|
} else {
|
||||||
|
if(INTERFACE_DATA.Timeout.draw !== null) {
|
||||||
|
INTERFACE_DATA.Timeout.draw = null;
|
||||||
|
setTimeout(INTERFACE.draw, 1000 / 30);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -882,6 +950,8 @@ const INTERFACE = {
|
|||||||
|
|
||||||
// Draw tile content
|
// Draw tile content
|
||||||
if(piece !== null) {
|
if(piece !== null) {
|
||||||
|
let piece_def = GAME.Const.Piece[piece.piece];
|
||||||
|
|
||||||
// Draw border hints
|
// Draw border hints
|
||||||
this.hints(piece);
|
this.hints(piece);
|
||||||
|
|
||||||
@ -889,9 +959,14 @@ const INTERFACE = {
|
|||||||
if(INTERFACE_DATA.mirror && (piece.player ^ (INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate) != 0) {
|
if(INTERFACE_DATA.mirror && (piece.player ^ (INTERFACE_DATA.player & 1) ^ INTERFACE_DATA.rotate) != 0) {
|
||||||
this.ctx.rotate(Math.PI);
|
this.ctx.rotate(Math.PI);
|
||||||
}
|
}
|
||||||
if(piece.promoted) { this.ctx.drawImage(GAME_ASSET.Image.Promote, -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.); }
|
if(piece.promoted) {
|
||||||
this.ctx.drawImage(GAME_ASSET.Image.Piece[piece.piece][piece.player], -icon_radius, -icon_radius, icon_radius * 2., icon_radius * 2.);
|
GAME_ASSET.Image.Promote.draw(this.ctx, 1.5 * this.scale, [0, 0], INTERFACE.Color.Promote);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(GAME_ASSET.Image[piece_def.name] !== undefined) {
|
||||||
|
let piece_color = (piece.player == GAME.Const.Player.Dawn)? INTERFACE.Color.Dawn : INTERFACE.Color.Dusk;
|
||||||
|
GAME_ASSET.Image[piece_def.name].draw(this.ctx, 1.5 * this.scale, [0, 0], piece_color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
@ -899,9 +974,10 @@ const INTERFACE = {
|
|||||||
|
|
||||||
pool(x, y, basis, player, mirror=false) {
|
pool(x, y, basis, player, mirror=false) {
|
||||||
let radius = INTERFACE.Radius * this.scale;
|
let radius = INTERFACE.Radius * this.scale;
|
||||||
let icon_radius = 0.69 * radius;
|
|
||||||
|
|
||||||
for(let i = 0; i < 7; ++i) {
|
for(let i = 0; i < 7; ++i) {
|
||||||
|
let piece_def = GAME.Const.Piece[i];
|
||||||
|
|
||||||
let tile_id = i + basis;
|
let tile_id = i + basis;
|
||||||
let is_hover = INTERFACE.Ui.tile_is_hover(1, tile_id);
|
let is_hover = INTERFACE.Ui.tile_is_hover(1, tile_id);
|
||||||
let is_select = INTERFACE.Ui.tile_is_select(1, tile_id);
|
let is_select = INTERFACE.Ui.tile_is_select(1, tile_id);
|
||||||
@ -960,8 +1036,10 @@ const INTERFACE = {
|
|||||||
this.ctx.rotate(Math.PI);
|
this.ctx.rotate(Math.PI);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw image
|
if(GAME_ASSET.Image[piece_def.name] !== undefined) {
|
||||||
this.ctx.drawImage(GAME_ASSET.Image.Piece[i][player], -icon_radius * 0.55, -icon_radius * 0.8, icon_radius * 1.6, icon_radius * 1.6);
|
let piece_color = (player == GAME.Const.Player.Dawn)? INTERFACE.Color.Dawn : INTERFACE.Color.Dusk;
|
||||||
|
GAME_ASSET.Image[piece_def.name].draw(this.ctx, radius, [0.2 * radius, 0], piece_color);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw count
|
// Draw count
|
||||||
this.ctx.fillStyle = player_color;
|
this.ctx.fillStyle = player_color;
|
||||||
@ -1013,9 +1091,6 @@ const INTERFACE = {
|
|||||||
let dusk = null;
|
let dusk = null;
|
||||||
|
|
||||||
INTERFACE_DATA = {
|
INTERFACE_DATA = {
|
||||||
mode: mode,
|
|
||||||
token: token,
|
|
||||||
|
|
||||||
canvas: document.getElementById("game"),
|
canvas: document.getElementById("game"),
|
||||||
context: null,
|
context: null,
|
||||||
|
|
||||||
@ -1028,19 +1103,46 @@ const INTERFACE = {
|
|||||||
clicked: null,
|
clicked: null,
|
||||||
alt_mode: false,
|
alt_mode: false,
|
||||||
|
|
||||||
handles: [dawn, dusk],
|
mode: mode,
|
||||||
board_state: [ ],
|
Session: {
|
||||||
resign:false,
|
token: token,
|
||||||
resign_warn:false,
|
Client: {
|
||||||
|
Dawn: {
|
||||||
|
handle: null,
|
||||||
|
online: false,
|
||||||
|
},
|
||||||
|
Dusk: {
|
||||||
|
handle: null,
|
||||||
|
online: false,
|
||||||
|
},
|
||||||
|
Spectators: {
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
history: [ ],
|
Game: {
|
||||||
history_begin: [ ],
|
board_state: [ ],
|
||||||
|
history: [ ],
|
||||||
replay_turn: 0,
|
history_begin: [ ],
|
||||||
replay_auto: false,
|
auto: null,
|
||||||
auto_mode: null,
|
},
|
||||||
|
|
||||||
Ui: {
|
Ui: {
|
||||||
|
request_undo:false,
|
||||||
|
resign_warn:false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Timeout: {
|
||||||
|
draw: null,
|
||||||
|
},
|
||||||
|
|
||||||
|
Replay: {
|
||||||
|
turn: 0,
|
||||||
|
auto: false,
|
||||||
|
},
|
||||||
|
|
||||||
|
Render: {
|
||||||
scale: 0,
|
scale: 0,
|
||||||
margin: { t:0, l:0, r:0, b:0 },
|
margin: { t:0, l:0, r:0, b:0 },
|
||||||
offset: new MATH.Vec2(),
|
offset: new MATH.Vec2(),
|
||||||
@ -1050,14 +1152,17 @@ const INTERFACE = {
|
|||||||
pool_offset: 0,
|
pool_offset: 0,
|
||||||
},
|
},
|
||||||
|
|
||||||
Animate: {
|
Animation: {
|
||||||
play: null,
|
|
||||||
piece: null,
|
piece: null,
|
||||||
target: null,
|
// play: null,
|
||||||
time: 0,
|
// piece: null,
|
||||||
|
// target: null,
|
||||||
|
// time: 0,
|
||||||
|
particles: [ ],
|
||||||
|
queue: [ ],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for(let i = 0; i < 61; ++i) { INTERFACE_DATA.board_state.push([0, 0]); }
|
for(let i = 0; i < 61; ++i) { INTERFACE_DATA.Game.board_state.push([0, 0]); }
|
||||||
|
|
||||||
let canvas = INTERFACE_DATA.canvas;
|
let canvas = INTERFACE_DATA.canvas;
|
||||||
if(canvas !== undefined) {
|
if(canvas !== undefined) {
|
||||||
@ -1068,11 +1173,11 @@ const INTERFACE = {
|
|||||||
canvas.addEventListener("mousedown", INTERFACE.click);
|
canvas.addEventListener("mousedown", INTERFACE.click);
|
||||||
canvas.addEventListener("mouseup", INTERFACE.release);
|
canvas.addEventListener("mouseup", INTERFACE.release);
|
||||||
canvas.addEventListener("contextmenu", INTERFACE.contextmenu);
|
canvas.addEventListener("contextmenu", INTERFACE.contextmenu);
|
||||||
window.addEventListener("resize", INTERFACE.draw);
|
window.addEventListener("resize", INTERFACE.step);
|
||||||
|
|
||||||
switch(INTERFACE_DATA.mode) {
|
switch(INTERFACE_DATA.mode) {
|
||||||
case INTERFACE.Mode.Local: {
|
case INTERFACE.Mode.Local: {
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1084,7 +1189,7 @@ const INTERFACE = {
|
|||||||
case INTERFACE.Mode.Player: {
|
case INTERFACE.Mode.Player: {
|
||||||
MESSAGE_COMPOSE([
|
MESSAGE_COMPOSE([
|
||||||
PACK.u16(OpCode.GameState),
|
PACK.u16(OpCode.GameState),
|
||||||
INTERFACE_DATA.token,
|
INTERFACE_DATA.Session.token,
|
||||||
]);
|
]);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -1104,23 +1209,23 @@ const INTERFACE = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
reset() {
|
reset() {
|
||||||
INTERFACE_DATA.auto_mode = null;
|
INTERFACE_DATA.Game.auto = null;
|
||||||
|
|
||||||
INTERFACE_DATA.history = [ ];
|
INTERFACE_DATA.Game.history = [ ];
|
||||||
for(let i = 0; i < INTERFACE_DATA.history_begin.length; ++i) {
|
for(let i = 0; i < INTERFACE_DATA.Game.history_begin.length; ++i) {
|
||||||
INTERFACE_DATA.history.push(INTERFACE_DATA.history_begin[i]);
|
INTERFACE_DATA.Game.history.push(INTERFACE_DATA.Game.history_begin[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERFACE_DATA.replay_turn = INTERFACE_DATA.history.length + 1;
|
INTERFACE_DATA.Replay.turn = INTERFACE_DATA.Game.history.length + 1;
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.history.length, false);
|
INTERFACE.replay_jump(INTERFACE_DATA.Game.history.length, false);
|
||||||
},
|
},
|
||||||
|
|
||||||
undo() {
|
undo() {
|
||||||
INTERFACE_DATA.auto_mode = null;
|
INTERFACE_DATA.Game.auto = null;
|
||||||
if(INTERFACE_DATA.history.length > 0) {
|
if(INTERFACE_DATA.Game.history.length > 0) {
|
||||||
INTERFACE_DATA.replay_turn = INTERFACE_DATA.history.length + 1;
|
INTERFACE_DATA.Replay.turn = INTERFACE_DATA.Game.history.length + 1;
|
||||||
INTERFACE_DATA.history.pop();
|
INTERFACE_DATA.Game.history.pop();
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.history.length, false);
|
INTERFACE.replay_jump(INTERFACE_DATA.Game.history.length, false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1133,33 +1238,93 @@ const INTERFACE = {
|
|||||||
INTERFACE_DATA.player = data.player;
|
INTERFACE_DATA.player = data.player;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERFACE_DATA.history = data.history;
|
INTERFACE_DATA.Game.history = data.history;
|
||||||
let turn = INTERFACE_DATA.history.length;
|
let turn = INTERFACE_DATA.Game.history.length;
|
||||||
|
|
||||||
if(INTERFACE_DATA.history.length > 0) {
|
if(INTERFACE_DATA.Game.history.length > 0) {
|
||||||
if(INTERFACE_DATA.replay_turn == 0) {
|
if(INTERFACE_DATA.Replay.turn == 0) {
|
||||||
if(INTERFACE_DATA.history[INTERFACE_DATA.history.length-1].source == 2) {
|
//if(INTERFACE_DATA.Game.history[INTERFACE_DATA.Game.history.length-1].source == 2) {
|
||||||
turn = 0;
|
// turn = 0;
|
||||||
}
|
//}
|
||||||
} else {
|
} else {
|
||||||
turn = INTERFACE_DATA.replay_turn;
|
turn = INTERFACE_DATA.Replay.turn;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(data.dawn.length > 0) { INTERFACE_DATA.handles[0] = data.dawn; }
|
if(data.dawn.length > 0) { INTERFACE_DATA.Session.Client.Dawn.handle = data.dawn; }
|
||||||
if(data.dusk.length > 0) { INTERFACE_DATA.handles[1] = data.dusk; }
|
if(data.dusk.length > 0) { INTERFACE_DATA.Session.Client.Dusk.handle = data.dusk; }
|
||||||
|
|
||||||
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
||||||
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " / " + INTERFACE_DATA.history.length;
|
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.Replay.turn + " / " + INTERFACE_DATA.Game.history.length;
|
||||||
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.history.length);
|
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.Game.history.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERFACE.replay_jump(turn);
|
INTERFACE.replay_jump(turn);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OpCode.GamePlay: {
|
case OpCode.GameMessage: {
|
||||||
if(data.status == Status.Ok && data.turn == INTERFACE_DATA.history.length) {
|
switch(data.code) {
|
||||||
INTERFACE.history_push(data.play, true);
|
case GameMessage.Error: break;
|
||||||
|
|
||||||
|
case GameMessage.Move: {
|
||||||
|
if(data.turn == INTERFACE_DATA.Game.history.length) {
|
||||||
|
INTERFACE.history_push(new GAME.Play(0, data.from, data.to), true);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GameMessage.Drop: {
|
||||||
|
if(data.turn == INTERFACE_DATA.Game.history.length) {
|
||||||
|
INTERFACE.history_push(new GAME.Play(1, data.piece, data.to), true);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case GameMessage.Alt: {
|
||||||
|
if(data.turn == INTERFACE_DATA.Game.history.length) {
|
||||||
|
INTERFACE.history_push(new GAME.Play(2, data.from, data.to), true);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Online: {
|
||||||
|
switch(data.client) {
|
||||||
|
case 0: {
|
||||||
|
// Spectator
|
||||||
|
INTERFACE_DATA.Session.Client.Spectators.count = data.state;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 1: {
|
||||||
|
// Dawn
|
||||||
|
INTERFACE_DATA.Session.Client.Dawn.online = (data.state != 0);
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 2: {
|
||||||
|
// Dusk
|
||||||
|
INTERFACE_DATA.Session.Client.Dawn.online = (data.state != 0);
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Undo: {
|
||||||
|
switch(data.state) {
|
||||||
|
case 0: {
|
||||||
|
// Request undo
|
||||||
|
if(data.turn == INTERFACE_DATA.Game.history.length) {
|
||||||
|
INTERFACE_DATA.Ui.request_undo = true;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
case 1: {
|
||||||
|
// Perform undo
|
||||||
|
INTERFACE.undo();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Retire: {
|
||||||
|
GAME_DATA.state.code = GAME.Const.State.Resign;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Reaction: {
|
||||||
|
INTERFACE_DATA.Animation.queue.push(data.index);
|
||||||
|
INTERFACE.reaction_generate();
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -1170,23 +1335,16 @@ const INTERFACE = {
|
|||||||
|
|
||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
case 0:
|
case 0:
|
||||||
case 3: {
|
case 2: {
|
||||||
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);
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 1: {
|
case 1: {
|
||||||
//let player = Math.floor(play.from / 7) ^ (INTERFACE_DATA.player & 1);
|
|
||||||
//if(INTERFACE_DATA.player == 2) { player ^= INTERFACE_DATA.rotate; }
|
|
||||||
//valid = player == (GAME_DATA.turn & 1);
|
|
||||||
play.from %= 7;
|
play.from %= 7;
|
||||||
valid = true;
|
valid = true;
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 2: {
|
|
||||||
valid = INTERFACE_DATA.mode == INTERFACE.Mode.Player;
|
|
||||||
} break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(valid) {
|
if(valid) {
|
||||||
@ -1196,21 +1354,29 @@ const INTERFACE = {
|
|||||||
case INTERFACE.Mode.Local: {
|
case INTERFACE.Mode.Local: {
|
||||||
INTERFACE.history_push(play, true);
|
INTERFACE.history_push(play, true);
|
||||||
|
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
|
|
||||||
if(INTERFACE_DATA.auto_mode !== null && INTERFACE_DATA.auto_mode == (GAME_DATA.turn & 1)) {
|
if(INTERFACE_DATA.Game.auto !== null && INTERFACE_DATA.Game.auto == (GAME_DATA.turn & 1)) {
|
||||||
setTimeout(INTERFACE.auto_play, 1000);
|
setTimeout(INTERFACE.auto_play, 1000);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
// 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 << 4) | (play.to << 10);
|
let msg = GAME_DATA.turn | (play.from << 16) | (play.to << 22);
|
||||||
|
|
||||||
|
let high = msg >> 24;
|
||||||
|
let low = (msg << 8) & 0xFFFF_FFFF;
|
||||||
|
switch(play.source) {
|
||||||
|
case 0: low |= GameMessage.Move; break;
|
||||||
|
case 1: low |= GameMessage.Drop; break;
|
||||||
|
case 2: low |= GameMessage.Alt; break;
|
||||||
|
}
|
||||||
|
|
||||||
MESSAGE_COMPOSE([
|
MESSAGE_COMPOSE([
|
||||||
PACK.u16(OpCode.GamePlay),
|
PACK.u16(OpCode.GameMessage),
|
||||||
PACK.u16(0),
|
PACK.u32(high),
|
||||||
PACK.u16(GAME_DATA.turn),
|
PACK.u32(low),
|
||||||
PACK.u16(move_data),
|
|
||||||
]);
|
]);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
@ -1219,12 +1385,12 @@ const INTERFACE = {
|
|||||||
|
|
||||||
rotate() {
|
rotate() {
|
||||||
INTERFACE_DATA.rotate ^= 1;
|
INTERFACE_DATA.rotate ^= 1;
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
},
|
},
|
||||||
|
|
||||||
mirror() {
|
mirror() {
|
||||||
INTERFACE_DATA.mirror = !INTERFACE_DATA.mirror;
|
INTERFACE_DATA.mirror = !INTERFACE_DATA.mirror;
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
},
|
},
|
||||||
|
|
||||||
resign() {
|
resign() {
|
||||||
@ -1235,7 +1401,7 @@ const INTERFACE = {
|
|||||||
INTERFACE.resign_reset();
|
INTERFACE.resign_reset();
|
||||||
MESSAGE_COMPOSE([
|
MESSAGE_COMPOSE([
|
||||||
PACK.u16(OpCode.SessionResign),
|
PACK.u16(OpCode.SessionResign),
|
||||||
INTERFACE_DATA.token,
|
INTERFACE_DATA.Session.token,
|
||||||
]);
|
]);
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.resign_warn = true;
|
INTERFACE_DATA.resign_warn = true;
|
||||||
@ -1258,12 +1424,12 @@ const INTERFACE = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
history_push(play, animate=false) {
|
history_push(play, animate=false) {
|
||||||
INTERFACE_DATA.history.push(play);
|
INTERFACE_DATA.Game.history.push(play);
|
||||||
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
||||||
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " / " + INTERFACE_DATA.history.length;
|
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.Replay.turn + " / " + INTERFACE_DATA.Game.history.length;
|
||||||
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.history.length);
|
document.getElementById("turn-slider").setAttribute("max", INTERFACE_DATA.Game.history.length);
|
||||||
}
|
}
|
||||||
if(INTERFACE_DATA.replay_turn == INTERFACE_DATA.history.length - 1) {
|
if(INTERFACE_DATA.Replay.turn == INTERFACE_DATA.Game.history.length - 1) {
|
||||||
INTERFACE.replay_next(animate);
|
INTERFACE.replay_next(animate);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1271,22 +1437,22 @@ const INTERFACE = {
|
|||||||
replay_jump(turn, animate=false) {
|
replay_jump(turn, animate=false) {
|
||||||
turn = +turn;
|
turn = +turn;
|
||||||
|
|
||||||
if(turn >= 0 && turn <= INTERFACE_DATA.history.length) {
|
if(turn >= 0 && turn <= INTERFACE_DATA.Game.history.length) {
|
||||||
if(turn <= INTERFACE_DATA.replay_turn) {
|
if(turn <= INTERFACE_DATA.Replay.turn) {
|
||||||
INTERFACE_DATA.replay_turn = 0;
|
INTERFACE_DATA.Replay.turn = 0;
|
||||||
GAME.init();
|
GAME.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
let play = null;
|
let play = null;
|
||||||
let piece = null;
|
let piece = null;
|
||||||
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.Game.history[INTERFACE_DATA.Replay.turn];
|
||||||
switch(play.source) {
|
switch(play.source) {
|
||||||
case 0:
|
case 0:
|
||||||
case 1:
|
case 1:
|
||||||
case 3: {
|
case 2: {
|
||||||
if(play.source == 0 || play.source == 3) {
|
if(play.source == 0 || play.source == 2) {
|
||||||
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
let piece_id = GAME_DATA.board.tiles[play.from].piece;
|
||||||
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
|
if(piece_id !== null) { piece = GAME_DATA.board.pieces[piece_id].clone(); }
|
||||||
|
|
||||||
@ -1309,47 +1475,49 @@ const INTERFACE = {
|
|||||||
play = null;
|
play = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
INTERFACE_DATA.replay_turn++;
|
INTERFACE_DATA.Replay.turn++;
|
||||||
}
|
}
|
||||||
if(animate && play !== null) {
|
if(animate && play !== null) {
|
||||||
INTERFACE_DATA.Animate.time = Date.now() + 500;
|
INTERFACE_DATA.Animation.piece = {
|
||||||
INTERFACE_DATA.Animate.play = play;
|
time: Date.now() + 500,
|
||||||
INTERFACE_DATA.Animate.piece = piece;
|
play: play,
|
||||||
INTERFACE_DATA.Animate.target = target;
|
piece: piece,
|
||||||
|
target: target,
|
||||||
|
};
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.Animate.play = null;
|
INTERFACE_DATA.Animation.piece = null;
|
||||||
}
|
}
|
||||||
INTERFACE_DATA.replay_turn = turn;
|
INTERFACE_DATA.Replay.turn = turn;
|
||||||
|
|
||||||
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
||||||
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.replay_turn + " / " + INTERFACE_DATA.history.length;
|
document.getElementById("indicator-turn").innerText = INTERFACE_DATA.Replay.turn + " / " + INTERFACE_DATA.Game.history.length;
|
||||||
document.getElementById("turn-slider").value = INTERFACE_DATA.replay_turn;
|
document.getElementById("turn-slider").value = INTERFACE_DATA.Replay.turn;
|
||||||
}
|
}
|
||||||
|
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replay_first() {
|
replay_first() {
|
||||||
INTERFACE.replay_jump(0);
|
INTERFACE.replay_jump(0);
|
||||||
},
|
},
|
||||||
replay_last(animate=false) {
|
replay_last(animate=false) {
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.history.length, animate);
|
INTERFACE.replay_jump(INTERFACE_DATA.Game.history.length, animate);
|
||||||
},
|
},
|
||||||
replay_prev(animate=false) {
|
replay_prev(animate=false) {
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn - 1, animate);
|
INTERFACE.replay_jump(INTERFACE_DATA.Replay.turn - 1, animate);
|
||||||
},
|
},
|
||||||
replay_next(animate=false) {
|
replay_next(animate=false) {
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn + 1, animate);
|
INTERFACE.replay_jump(INTERFACE_DATA.Replay.turn + 1, animate);
|
||||||
},
|
},
|
||||||
replay_toggle_auto() {
|
replay_toggle_auto() {
|
||||||
INTERFACE_DATA.replay_auto = !INTERFACE_DATA.replay_auto;
|
INTERFACE_DATA.Replay.auto = !INTERFACE_DATA.Replay.auto;
|
||||||
if(INTERFACE_DATA.replay_auto) {
|
if(INTERFACE_DATA.Replay.auto) {
|
||||||
setTimeout(INTERFACE.replay_auto, 1000);
|
setTimeout(INTERFACE.replay_auto, 1000);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
replay_auto() {
|
replay_auto() {
|
||||||
if(INTERFACE_DATA.replay_auto) {
|
if(INTERFACE_DATA.Replay.auto) {
|
||||||
INTERFACE.replay_jump(INTERFACE_DATA.replay_turn + 1, true);
|
INTERFACE.replay_jump(INTERFACE_DATA.Replay.turn + 1, true);
|
||||||
setTimeout(INTERFACE.replay_auto, 1100);
|
setTimeout(INTERFACE.replay_auto, 1100);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1359,17 +1527,17 @@ const INTERFACE = {
|
|||||||
|
|
||||||
|
|
||||||
auto() {
|
auto() {
|
||||||
if(INTERFACE_DATA.auto_mode === null) {
|
if(INTERFACE_DATA.Game.auto === null) {
|
||||||
INTERFACE_DATA.auto_mode = INTERFACE_DATA.rotate ^ 1;
|
INTERFACE_DATA.Game.auto = INTERFACE_DATA.rotate ^ 1;
|
||||||
setTimeout(INTERFACE.auto_play, 500);
|
setTimeout(INTERFACE.auto_play, 500);
|
||||||
} else {
|
} else {
|
||||||
INTERFACE_DATA.auto_mode = null;
|
INTERFACE_DATA.Game.auto = null;
|
||||||
}
|
}
|
||||||
INTERFACE.draw();
|
INTERFACE.step();
|
||||||
},
|
},
|
||||||
|
|
||||||
auto_play() {
|
auto_play() {
|
||||||
if(INTERFACE_DATA.auto_mode !== (GAME_DATA.turn & 1) || GAME_DATA.state.checkmate) { return; }
|
if(INTERFACE_DATA.Game.auto !== (GAME_DATA.turn & 1) || GAME_DATA.state.checkmate) { return; }
|
||||||
|
|
||||||
function state_score(state, player) {
|
function state_score(state, player) {
|
||||||
let score = 0;
|
let score = 0;
|
||||||
@ -1516,11 +1684,6 @@ const INTERFACE = {
|
|||||||
|
|
||||||
let result = determine_play(GAME_DATA, GAME_DATA.turn & 1, 1);
|
let result = determine_play(GAME_DATA, GAME_DATA.turn & 1, 1);
|
||||||
if(result !== null) {
|
if(result !== null) {
|
||||||
// Add 7 to tile to indicate Dusk player pool.
|
|
||||||
//if(result.play.source == 1 && (GAME_DATA.turn & 1) === 1) {
|
|
||||||
// result.play.from += 7;
|
|
||||||
//}
|
|
||||||
|
|
||||||
INTERFACE.process(result.play);
|
INTERFACE.process(result.play);
|
||||||
} else {
|
} else {
|
||||||
console.log("warn: autoplay move was null.");
|
console.log("warn: autoplay move was null.");
|
||||||
@ -1541,6 +1704,43 @@ const INTERFACE = {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
react()
|
||||||
|
{
|
||||||
|
if(INTERFACE_DATA.mode == INTERFACE.Mode.Review) {
|
||||||
|
let high = 0;
|
||||||
|
let low = GameMessage.Reaction;
|
||||||
|
|
||||||
|
MESSAGE_COMPOSE([
|
||||||
|
PACK.u16(OpCode.GameMessage),
|
||||||
|
PACK.u32(high),
|
||||||
|
PACK.u32(low),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reaction_generate()
|
||||||
|
{
|
||||||
|
if(INTERFACE_DATA !== null) {
|
||||||
|
if(INTERFACE_DATA.Animation.queue.length > 0) {
|
||||||
|
let index = INTERFACE_DATA.Animation.queue.pop();
|
||||||
|
INTERFACE_DATA.Animation.particles.push({
|
||||||
|
index:index,
|
||||||
|
color:0,
|
||||||
|
scale:1.75 + (Math.random() * 0.25),
|
||||||
|
position:[0, 0],
|
||||||
|
rotation:0,
|
||||||
|
velocity:[1 - (Math.random() * 2), 2 + (Math.random() * 4)],
|
||||||
|
angular:0.01 - (Math.random() * 0.02),
|
||||||
|
time:1.5 + (Math.random() * 1.5),
|
||||||
|
});
|
||||||
|
if(INTERFACE_DATA.Timeout.draw === null) {
|
||||||
|
INTERFACE_DATA.Timeout.draw = setTimeout(INTERFACE.draw, 1);
|
||||||
|
}
|
||||||
|
setTimeout(INTERFACE.reaction_generate, 50);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
INTERFACE.TileScale = 0.9;
|
INTERFACE.TileScale = 0.9;
|
||||||
|
@ -620,10 +620,13 @@ const SCENES = {
|
|||||||
load(data) {
|
load(data) {
|
||||||
// Bottom Buttons
|
// Bottom Buttons
|
||||||
let buttons_bottom = [ ];
|
let buttons_bottom = [ ];
|
||||||
if(data.mode != INTERFACE.Mode.Review) {
|
if(data.mode == INTERFACE.Mode.Player) {
|
||||||
let button_resign = UI.button(LANG("resign"), () => { INTERFACE.resign(); });
|
let button_resign = UI.button(LANG("resign"), () => { INTERFACE.resign(); });
|
||||||
button_resign.setAttribute("id", "button-resign");
|
button_resign.setAttribute("id", "button-resign");
|
||||||
buttons_bottom.push(button_resign);
|
buttons_bottom.push(button_resign);
|
||||||
|
} else {
|
||||||
|
let button_react = UI.button("Clap", () => { INTERFACE.react(); });
|
||||||
|
buttons_bottom.push(button_react);
|
||||||
}
|
}
|
||||||
buttons_bottom.push(UI.button(LANG("back"), () => {
|
buttons_bottom.push(UI.button(LANG("back"), () => {
|
||||||
LOAD(SCENES.Browse);
|
LOAD(SCENES.Browse);
|
||||||
@ -728,12 +731,7 @@ const SCENES = {
|
|||||||
INTERFACE.uninit();
|
INTERFACE.uninit();
|
||||||
}
|
}
|
||||||
message(code, data) {
|
message(code, data) {
|
||||||
switch(code) {
|
INTERFACE.message(code, data);
|
||||||
case OpCode.GameState:
|
|
||||||
case OpCode.GamePlay: {
|
|
||||||
INTERFACE.message(code, data);
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
disconnect() {
|
disconnect() {
|
||||||
LOAD(SCENES.Offline);
|
LOAD(SCENES.Offline);
|
||||||
|
@ -309,30 +309,61 @@ function MESSAGE(event) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OpCode.GamePlay: {
|
case OpCode.GameMessage: {
|
||||||
console.log("RECV GamePlay");
|
console.log("RECV GameMessage");
|
||||||
|
|
||||||
|
result = UNPACK.u32(bytes, index);
|
||||||
|
index = result.index;
|
||||||
|
let high = result.data;
|
||||||
|
|
||||||
|
result = UNPACK.u32(bytes, index);
|
||||||
|
index = result.index;
|
||||||
|
let low = result.data;
|
||||||
|
|
||||||
|
let opcode = low & 0xFF;
|
||||||
|
let dat = ((low >> 8) & 0xFFFFFF) | ((high & 0xFF) << 24);
|
||||||
|
let ext = (high >> 8) & 0xFFFFFF;
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
status:0,
|
code:opcode,
|
||||||
play:new GAME.Play(0, 0, 0),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Status
|
switch(opcode) {
|
||||||
result = UNPACK.u16(bytes, index);
|
case GameMessage.Error: { } break;
|
||||||
index = result.index;
|
|
||||||
data.status = result.data;
|
|
||||||
|
|
||||||
// Turn
|
case GameMessage.Move: {
|
||||||
result = UNPACK.u16(bytes, index);
|
data.turn = dat & 0xFFFF;
|
||||||
index = result.index;
|
data.from = (dat >> 16) & 0x3F;
|
||||||
data.turn = result.data;
|
data.to = (dat >> 22) & 0x3F;
|
||||||
|
} break;
|
||||||
|
|
||||||
// Play description
|
case GameMessage.Drop: {
|
||||||
result = UNPACK.u16(bytes, index);
|
data.turn = dat & 0xFFFF;
|
||||||
index = result.index;
|
data.piece = (dat >> 16) & 0x3F;
|
||||||
data.play.source = result.data & 0xF;
|
data.to = (dat >> 22) & 0x3F;
|
||||||
data.play.from = (result.data >> 4) & 0x3F;
|
} break;
|
||||||
data.play.to = (result.data >> 10) & 0x3F;
|
|
||||||
|
case GameMessage.Alt: {
|
||||||
|
data.turn = dat & 0xFFFF;
|
||||||
|
data.from = (dat >> 16) & 0x3F;
|
||||||
|
data.to = (dat >> 22) & 0x3F;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Online: {
|
||||||
|
data.client = dat & 0x3;
|
||||||
|
data.state = (dat & 0x4) != 0;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Undo: {
|
||||||
|
data.state = dat & 0x3;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case GameMessage.Retire: { } break;
|
||||||
|
|
||||||
|
case GameMessage.Reaction: {
|
||||||
|
data.index = dat & 0xFFFF;
|
||||||
|
} break;
|
||||||
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case OpCode.ChallengeAnswer: {
|
case OpCode.ChallengeAnswer: {
|
||||||
|