add onshowscene and get_current_scene functions

This commit is contained in:
Rusty Striker 2025-06-16 20:57:51 +03:00
parent f59c06c348
commit 731f22a2c2
Signed by: RustyStriker
GPG key ID: 87E4D691632DFF15
7 changed files with 188 additions and 103 deletions

View file

@ -38,8 +38,6 @@ function init() {
} }
document.body.onmousemove = onMoveableDivDrag; document.body.onmousemove = onMoveableDivDrag;
document.body.onmouseup = onMoveableDivMouseUp; document.body.onmouseup = onMoveableDivMouseUp;
// TODO: Remove when done dev-ing
tavern.onmessage({ text: 'test', id: 1, source: 'rusty', character: 'bart' });
} }
tavern.onlogin = (s) => { tavern.onlogin = (s) => {
@ -50,7 +48,7 @@ tavern.onlogin = (s) => {
game.style.display = 'flex'; game.style.display = 'flex';
// get last 50 msgs (i think that is enough for now) when we get in // get last 50 msgs (i think that is enough for now) when we get in
tavern.get_last_msgs(50); tavern.get_last_msgs(50);
tavern.get_tokens(); tavern.get_current_scene();
} }
else { else {
alert("Invalid username or password!"); alert("Invalid username or password!");
@ -131,6 +129,15 @@ tavern.onmovetoken = (m) => {
token.style.left = `${m.x * GRID_SIZE}px`; token.style.left = `${m.x * GRID_SIZE}px`;
} }
} }
tavern.onshowscene = (show) => {
let map = document.getElementById('map');
// Remove existing tokens
Array.from(map.children).filter(c => c.classList.contains('token')).forEach(c => map.removeChild(c));
for (let token of show.tokens) {
tavern.onspawntoken(token);
}
}
function onLoginClick() { function onLoginClick() {
let username = document.getElementById('login-username').value; let username = document.getElementById('login-username').value;
let pass = document.getElementById('login-pass').value; let pass = document.getElementById('login-pass').value;

View file

@ -1,11 +1,14 @@
html, body { html,
body {
margin: 0; margin: 0;
height: 100%; height: 100%;
} }
body { body {
background-color: rgb(32, 35, 35); background-color: rgb(32, 35, 35);
color: white; color: white;
} }
#side-panel { #side-panel {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
@ -18,6 +21,7 @@ body{
max-width: 50%; max-width: 50%;
background-image: linear-gradient(135deg, #0f0f2f 0px, #0f0f2f 99%, rgb(188, 255, 185) 100%); background-image: linear-gradient(135deg, #0f0f2f 0px, #0f0f2f 99%, rgb(188, 255, 185) 100%);
} }
#chat-history { #chat-history {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -28,6 +32,7 @@ body{
margin-top: 10px; margin-top: 10px;
background-color: #0f0f2f; background-color: #0f0f2f;
} }
.chat-message { .chat-message {
background-color: #ffffd6; background-color: #ffffd6;
color: #000000; color: #000000;
@ -40,33 +45,40 @@ body{
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
#msg-context-menu { #msg-context-menu {
display: none; display: none;
position: absolute; position: absolute;
z-index: 1000; z-index: 1000;
padding: 4px; padding: 4px;
} }
#msg-context-menu ul { #msg-context-menu ul {
padding: 0px; padding: 0px;
margin: 0px; margin: 0px;
list-style: none; list-style: none;
} }
#msg-context-menu ul li { #msg-context-menu ul li {
padding: 4px; padding: 4px;
} }
#msg-context-menu ul li:hover { #msg-context-menu ul li:hover {
background: darkgray; background: darkgray;
cursor: pointer; cursor: pointer;
} }
.token { .token {
position: absolute; position: absolute;
} }
.token-transition { .token-transition {
transition: transition:
top 0.5s ease-in, top 0.1s ease-in,
left 0.5s ease-in; left 0.1s ease-in;
} }
.token img { .token img {
cursor: grab; cursor: grab;
width: 200px; width: 200px;

View file

@ -3,6 +3,7 @@ const tavern = {
msgs: [], msgs: [],
connected: false, connected: false,
loggedIn: false, loggedIn: false,
currentScene: 0,
call: (f, ...args) => { call: (f, ...args) => {
if (typeof (f) == "function") { if (typeof (f) == "function") {
f(...args); f(...args);
@ -55,6 +56,10 @@ tavern.socket.onmessage = (m) => {
if (m.move_token) { if (m.move_token) {
tavern.call(tavern.onmovetoken, m.move_token); tavern.call(tavern.onmovetoken, m.move_token);
} }
if (m.show_scene) {
tavern.currentScene = m.show_scene.scene;
tavern.call(tavern.onshowscene, m.show_scene);
}
} }
tavern.login = (username, password) => { tavern.login = (username, password) => {
if (!tavern.connected || tavern.loggedIn) { return false; } if (!tavern.connected || tavern.loggedIn) { return false; }
@ -79,9 +84,9 @@ tavern.get_last_msgs = (amount) => {
if (!tavern.connected || tavern.loggedIn) { return false; } if (!tavern.connected || tavern.loggedIn) { return false; }
tavern.socket.send(JSON.stringify({ get_last_messages: { amount: amount } })) tavern.socket.send(JSON.stringify({ get_last_messages: { amount: amount } }))
} }
tavern.get_tokens = () => { tavern.get_tokens = (mapId) => {
if (!tavern.connected || tavern.loggedIn) { return false; } if (!tavern.connected || tavern.loggedIn) { return false; }
tavern.socket.send(JSON.stringify('get_tokens')); tavern.socket.send(JSON.stringify({ get_tokens: { scene: mapId } }));
} }
tavern.move_token = (id, x, y) => { tavern.move_token = (id, x, y) => {
if (!tavern.connected || tavern.loggedIn) { return false; } if (!tavern.connected || tavern.loggedIn) { return false; }
@ -91,3 +96,7 @@ tavern.action_result = (name, source, targets, results) => {
if (!tavern.connected || tavern.loggedIn) { return false; } if (!tavern.connected || tavern.loggedIn) { return false; }
tavern.socket.send(JSON.stringify({ action_result: { name: name, source: source ?? '', targets: targets ?? [], results: results } })); tavern.socket.send(JSON.stringify({ action_result: { name: name, source: source ?? '', targets: targets ?? [], results: results } }));
} }
tavern.get_current_scene = () => {
if (!tavern.connected || tavern.loggedIn) { return; }
tavern.socket.send(JSON.stringify('get_current_scene'))
}

View file

@ -1,7 +1,5 @@
//! General game actions //! General game actions
use serde::{Serialize, Deserialize}; use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Ping { pub struct Ping {
@ -14,7 +12,7 @@ pub struct Ping {
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct ShowImage { pub struct ShowImage {
/// Which texture to show /// Which texture to show
pub texture: String pub texture: String,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
@ -22,11 +20,11 @@ pub struct SpawnToken {
pub token_id: usize, pub token_id: usize,
pub x: f32, pub x: f32,
pub y: f32, pub y: f32,
pub img: String pub img: String,
} }
impl std::fmt::Debug for SpawnToken { impl std::fmt::Debug for SpawnToken {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// I dont want it to print the `img` field because it VERY long :) // I dont want it to print the `img` field because it is VERY long :)
f.debug_struct("SpawnToken") f.debug_struct("SpawnToken")
.field("token_id", &self.token_id) .field("token_id", &self.token_id)
.field("x", &self.x) .field("x", &self.x)

View file

@ -1,5 +1,5 @@
pub mod login;
pub mod game_actions; pub mod game_actions;
pub mod login;
pub mod map_actions; pub mod map_actions;
use game_actions::SpawnToken; use game_actions::SpawnToken;
@ -19,21 +19,53 @@ pub enum Request {
Shutdown, Shutdown,
// Character stuff // Character stuff
CreateCharacter, CreateCharacter,
CharacterDisplay { id: usize }, CharacterDisplay {
CharacterInputs { id: usize }, id: usize,
CharacterGetField { id: usize, field: String }, },
CharacterSetField { id: usize, field: String, val: EntryType }, CharacterInputs {
CharacterAssign { id: usize, user: String }, id: usize,
},
CharacterGetField {
id: usize,
field: String,
},
CharacterSetField {
id: usize,
field: String,
val: EntryType,
},
CharacterAssign {
id: usize,
user: String,
},
// Chat requests // Chat requests
Message(ChatMessage), Message(ChatMessage),
GetChatHistory { amount: usize, from: usize }, GetChatHistory {
GetLastMessages { amount: usize, }, amount: usize,
from: usize,
},
GetLastMessages {
amount: usize,
},
// Map requests // Map requests
GetTokens { scene: usize }, GetCurrentScene,
SpawnToken { map_id: usize, character: String, x: f32, y: f32, img_path: String }, GetTokens {
MoveToken { token_id: usize, x: f32, y: f32 }, scene: usize,
},
SpawnToken {
map_id: usize,
character: String,
x: f32,
y: f32,
img_path: String,
},
MoveToken {
token_id: usize,
x: f32,
y: f32,
},
// Actions requests // Actions requests
ActionResult(ActionResult) ActionResult(ActionResult),
} }
#[derive(Serialize, Clone, Debug)] #[derive(Serialize, Clone, Debug)]
@ -43,12 +75,12 @@ pub enum Response {
Login(login::LoginResult), Login(login::LoginResult),
Message(ChatMessage), Message(ChatMessage),
GetChatHistory(Vec<ChatMessage>), GetChatHistory(Vec<ChatMessage>),
ShowScene { scene: usize, tokens: Vec<SpawnToken> },
MoveToken { token_id: usize, x: f32, y: f32 }, MoveToken { token_id: usize, x: f32, y: f32 },
SpawnToken(SpawnToken), SpawnToken(SpawnToken),
CharacterCreated(usize), CharacterCreated(usize),
Quit { id: String }, Quit { id: String },
Shutdown, Shutdown,
} }
#[derive(Serialize, Debug, Clone)] #[derive(Serialize, Debug, Clone)]

View file

@ -42,7 +42,7 @@ impl GameServer {
ActionDefinition::new("weapon/attack".to_string()) ActionDefinition::new("weapon/attack".to_string())
.display_name(Some("Attack +7".to_string())) .display_name(Some("Attack +7".to_string()))
.with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1)) .with_roll(DiceRoll::new("Pierce".to_string(), 12, 1).constant(1))
.with_roll(DiceRoll::new("Fire".to_string(), 4, 2)), .with_roll(DiceRoll::new("Fire".to_string(), 4, 2).enabled(false)),
) )
.with_action(ActionDefinition::new("Attack +3".to_string()).with_roll(DiceRoll::new( .with_action(ActionDefinition::new("Attack +3".to_string()).with_roll(DiceRoll::new(
"Base".to_string(), "Base".to_string(),
@ -158,6 +158,33 @@ impl GameServer {
} }
} }
} }
api::Request::GetCurrentScene => {
let scene = self.game.current_scene();
let mut scene_tokens = self
.game
.available_tokens(scene)
.iter()
.map(|id| self.game.token_info(0, *id).map(|info| (id, info)))
.flatten()
.map(|(id, info)| SpawnToken {
token_id: *id,
x: info.x,
y: info.y,
img: info.img_source.clone(),
})
.collect::<Vec<_>>();
for spawn in scene_tokens.iter_mut() {
let bits = std::fs::read(&spawn.img).expect("FAILED READING TOKEN IMAGE");
spawn.img = base64::Engine::encode(&base64::prelude::BASE64_STANDARD, &bits);
}
_ = broadcast.send((
Some(id.clone()),
api::Response::ShowScene {
scene: scene,
tokens: scene_tokens,
},
));
}
api::Request::SpawnToken { api::Request::SpawnToken {
map_id, map_id,
character, character,

View file

@ -111,9 +111,9 @@ async fn handle_socket(
b = brecv.recv() => { b = brecv.recv() => {
println!("{} trying to log in: {:?}", &temp_id, &b); println!("{} trying to log in: {:?}", &temp_id, &b);
if let Ok((to_id, msg)) = b { if let Ok((to_id, msg)) = b {
if let Response::Login(open_tavern::api::login::LoginResult { success, username }) = msg.clone() { if let Response::Login(open_tavern::api::login::LoginResult { success, username }) = &msg {
let to_id = to_id.map(|ti| ti == temp_id).unwrap_or(false); let to_id = to_id.map(|ti| ti == temp_id).unwrap_or(false);
if to_id && success && id.as_ref().map(|id| id == &username).unwrap_or(false) { if to_id && *success && id.as_ref().map(|id| id == username).unwrap_or(false) {
_ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default().into())).await; _ = socket.send(Message::Text(serde_json::to_string(&msg).unwrap_or_default().into())).await;
break; break;
} }