diff --git a/client/src/assets/base.css b/client/src/assets/base.css
index 388ad274..32ddb187 100644
--- a/client/src/assets/base.css
+++ b/client/src/assets/base.css
@@ -71,13 +71,14 @@
--chat-background: var(--c-white);
--section-gap: 160px;
+ --separator-color: #2e2e2e;
}
@media (prefers-color-scheme: dark) {
:root {
--window-background: var(--c-black-blurred);
- --color-handler: var(--c-black-semisoft);
+ --color-handler: #181818;
--color-background: var(--c-black);
--color-background-semisoft: var(--c-black-semisoft);
--color-background-soft: var(--c-black-soft);
@@ -98,8 +99,9 @@
--color-chat-other: #1d1d1d;
--color-roll-dice-chat: #665750;
+ --separator-color: #363636;
- --color-hover: var()
+ /* --color-hover: var() */
}
}
diff --git a/client/src/assets/main.css b/client/src/assets/main.css
index 29c747f3..bb234972 100644
--- a/client/src/assets/main.css
+++ b/client/src/assets/main.css
@@ -143,4 +143,25 @@ button:active {
margin-left: auto;
margin-right: auto;
display: block;
+}
+
+.parameters {
+ display: flex;
+ flex-direction: column;
+ width: 100%;
+ padding: 10px;
+}
+
+.param-element {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+}
+
+.param-text {
+ margin-right: auto;
+}
+
+.param-value {
+ margin-left: auto;
}
\ No newline at end of file
diff --git a/client/src/services/Map.js b/client/src/services/Map.js
new file mode 100644
index 00000000..1c9ade4a
--- /dev/null
+++ b/client/src/services/Map.js
@@ -0,0 +1,191 @@
+import { initCustomFormatter, ref } from 'vue';
+
+let offsetX = 0;
+let offsetY = 0;
+let scale = 1;
+
+let mouseX = 0;
+let mouseY = 0;
+
+function SetupTilemap(){
+ let tilemap = document.getElementById("tilemap");
+ tilemap.addEventListener("wheel", (event) => {
+ let direction = 0;
+ if(event.deltaY > 0) direction = 0.95;
+ else if(event.deltaY < 0) direction = 1.05;
+
+ zoom(direction);
+ })
+
+ let mouseDown = false;
+ let startX = 0, startY = 0;
+ let oldOffsetX = offsetX, oldOffsetY = offsetY;
+
+ tilemap.addEventListener("mousedown", (event) => {
+ mouseDown = true
+ startX = event.clientX;
+ startY = event.clientY;
+ oldOffsetX = offsetX;
+ oldOffsetY = offsetY;
+ });
+
+ tilemap.addEventListener("mousemove", (event) => {
+ mouseX = event.clientX;
+ mouseY = event.clientY;
+
+ if(!mouseDown) return;
+ offsetX = oldOffsetX + ((event.clientX - startX) * (1 / scale));
+ offsetY = oldOffsetY + ((event.clientY - startY) * (1 / scale));
+
+ Draw();
+ });
+
+ tilemap.addEventListener("mouseup", () => mouseDown = false);
+
+ addEventListener("resize", Draw)
+
+ offsetX = window.innerWidth / 2;
+ offsetY = window.innerHeight / 2;
+
+ Draw();
+}
+
+// Map coords -> Real coords
+function toMapX(xReal) {
+ return (xReal + offsetX) * scale;
+}
+
+function toMapY(yReal){
+ return (yReal + offsetY) * scale;
+}
+
+// Real coords -> Map coords
+function toRealX(xVirt){
+ return xVirt / scale - offsetX;
+}
+
+function toRealY(yVirt){
+ return yVirt / scale - offsetY;
+}
+
+function zoom(amount){
+ let dx = ((mouseX) / scale - offsetX) - ((mouseX) / (scale * amount) - offsetX)
+ let dy = ((mouseY) / scale - offsetY) - ((mouseY) / (scale * amount) - offsetY)
+ scale *= amount;
+ offsetX -= dx;
+ offsetY -= dy;
+ Draw();
+}
+
+let xUpperLeft = -Infinity;
+let yUpperLeft = -Infinity;
+let xDownRight = Infinity;
+let yDownRight = Infinity;
+
+function drawGrid(cellSize){
+ let canvas = document.getElementById('tilemap');
+
+ const width = canvas.clientWidth;
+ const height = canvas.clientHeight;
+
+ let ctx = canvas.getContext("2d");
+
+ ctx.strokeStyle = "#434343";
+ ctx.lineWidth = 1;
+
+ ctx.beginPath();
+
+ for (let x = (offsetX % cellSize) * scale; x <= width; x += cellSize * scale) {
+ if(toRealX(x) < xUpperLeft) continue;
+ if(toRealX(x) > xDownRight) continue;
+
+ ctx.moveTo(x, Math.max(0, toMapY(yUpperLeft)));
+ ctx.lineTo(x, Math.min(height, toMapY(yDownRight)));
+ }
+
+ for (let y = (offsetY % cellSize) * scale; y <= height; y += cellSize * scale) {
+ if(toRealY(y) < yUpperLeft) continue;
+ if(toRealY(y) > yDownRight) continue;
+ ctx.moveTo(Math.max(0, toMapX(xUpperLeft)), y);
+ ctx.lineTo(Math.min(width, toMapX(xDownRight)), y);
+ }
+
+
+ ctx.stroke();
+
+ ctx.strokeStyle = "red";
+ ctx.lineWidth = 1;
+
+ ctx.beginPath();
+ ctx.rect(toMapX(-10), toMapY(-10), 10 * scale, 10 * scale);
+ ctx.stroke();
+}
+
+// Ok aqui coses del mapa en si
+let gridSize = 150;
+let images = [];
+let lines_of_sight = [];
+let backgroundColor = ref('#0f0f0f');
+
+function Draw(){
+ let canvas = document.getElementById('tilemap');
+ let ctx = canvas.getContext("2d");
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+
+ images.forEach((image) => {
+ ctx.drawImage(image, toMapX(0), toMapY(0), image.naturalWidth * scale, image.naturalHeight * scale);
+ });
+
+
+ ctx.beginPath();
+ ctx.strokeStyle = "white";
+ ctx.lineWidth = 3;
+ lines_of_sight.forEach((line) => {
+ ctx.moveTo(toMapX(line[0].x * gridSize), toMapY(line[0].y * gridSize));
+ ctx.lineTo(toMapX(line[1].x * gridSize), toMapY(line[1].y * gridSize));
+ });
+ ctx.stroke();
+
+ drawGrid(gridSize);
+}
+
+function ImportDD2VTT(data){
+ console.log(data);
+
+ var image = new Image();
+ image.onload = function() {
+ images.push(image);
+ Draw();
+ };
+
+ gridSize = data.resolution.pixels_per_grid;
+ lines_of_sight = data.line_of_sight;
+ backgroundColor.value = '#' + data.environment.ambient_light;
+
+ xUpperLeft = data.resolution.map_origin.x * data.resolution.pixels_per_grid;
+ yUpperLeft = data.resolution.map_origin.y * data.resolution.pixels_per_grid;
+ xDownRight = xUpperLeft + data.resolution.map_size.x * data.resolution.pixels_per_grid;
+ yDownRight = yUpperLeft + data.resolution.map_size.y * data.resolution.pixels_per_grid;
+
+
+ image.src = "data:image/png;base64," + data.image;
+
+}
+
+let GetBackgroundColor = () => backgroundColor;
+
+export {
+ toMapX,
+ toMapY,
+ toRealX,
+ toRealY,
+ zoom,
+
+ SetupTilemap,
+ // Draw,
+ ImportDD2VTT,
+ GetBackgroundColor,
+};
\ No newline at end of file
diff --git a/client/src/services/Windows.js b/client/src/services/Windows.js
index ab70af77..2c486649 100644
--- a/client/src/services/Windows.js
+++ b/client/src/services/Windows.js
@@ -1,30 +1,16 @@
import { reactive, ref } from 'vue'
import { Disconnect } from './Dragonroll';
-const windows = {
- login: ref([]),
- register: ref([]),
- test: ref([]),
- main_menu: ref([]),
- edit_profile: ref([]),
- account_settings: ref([]),
- db_window: ref([]),
- campaign_list: ref([]),
- new_campaign: ref([]),
- join_campaign: ref([]),
- campaign_preview: ref([]),
- chat: ref([]),
- dice_menu: ref([]),
-};
+const windows = ref([])
const defValues = {
'login': {
id: 'login',
- title: 'Login'
+ title: 'Login',
},
'register': {
id: 'register',
- title: 'Register'
+ title: 'Register',
},
'main_menu': {
id: 'main_menu',
@@ -78,6 +64,16 @@ const defValues = {
id: 'dice_menu',
title: 'Dice roll',
close: true
+ },
+ 'map_buttons': {
+ id: 'map_buttons',
+ title: '',
+ close: true
+ },
+ 'environment': {
+ id: 'environment',
+ title: 'Edit environment',
+ close: true
}
}
@@ -166,6 +162,11 @@ function SetPosition(id, pos){
SaveWindowPos({id, x: pos.x, y: pos.y})
}
+function GetPosition(id){
+ let win = GetWindowWithId(id);
+ return {x: win.x, y: win.y};
+}
+
function ResetPosition(id, pos){
let win = GetWindowWithId(id);
let data = {x: win.x, y: win.y};
@@ -181,22 +182,18 @@ function ResetPosition(id, pos){
function CreateWindow(type, data = {}){
let finalData = {...{type}, ...defValues[type], ...data}
- if(windows[finalData.type] === undefined){
- console.error("Window type " + finalData.type + " is not defined!");
- return;
- }
-
let contains = false;
- for (let i = 0; i < windows[finalData.type].value.length; i++) {
- if(windows[finalData.type].value[i].id == finalData.id){
+ for (let i = 0; i < windows.value.length; i++) {
+ if(windows.value[i].id == finalData.id){
contains = true;
break;
}
}
if(!contains) {
- windows[finalData.type].value.push(finalData);
+ windows.value.push(finalData);
// reload.value += 1;
+ console.log(windows.value);
setTimeout(() => SetOnTop(finalData.id), 0);
}
}
@@ -212,7 +209,7 @@ function CreateChildWindow(parentId, type, data = {}){
function ClearAll(){
Object.keys(windows).forEach((key) => {
- windows[key].value = [];
+ windows.value = [];
});
}
@@ -227,16 +224,14 @@ function ClearWindow(id){
let win = GetWindowWithId(id);
if(!win) return;
if(win.children) for(let i = 0; i < win.children.length; i++) ClearWindow(win.children[i]);
- windows[win.type].value = windows[win.type].value.filter((e) => {return e.id !== id});
+ windows.value = windows.value.filter((e) => {return e.id !== id});
// reload.value += 1;
}
function GetWindowWithId(id){
- for(let key of Object.keys(windows)){
- for(let i = 0; i < windows[key].value.length; i++){
- if(windows[key].value[i].id == id){
- return windows[key].value[i];
- }
+ for(let i = 0; i < windows.value.length; i++){
+ if(windows.value[i].id == id){
+ return windows.value[i];
}
}
}
@@ -268,6 +263,7 @@ export {
CreateChildWindow,
GetWindowWithId,
SaveWindowPos,
+ GetPosition,
ClearWindow,
ClearAll
}
\ No newline at end of file
diff --git a/client/src/views/managers/GameManager.vue b/client/src/views/managers/GameManager.vue
index 98c86356..a3865b38 100644
--- a/client/src/views/managers/GameManager.vue
+++ b/client/src/views/managers/GameManager.vue
@@ -4,11 +4,12 @@ import { InGameRef } from '../../services/Game';
import IconButton from '../partials/game/IconButton.vue';
import { AddSound } from '../../services/Sound';
import TileMap from './TileMap.vue';
-import { DisplayCampaign, GetCampaign } from '../../services/Dragonroll';
+import { DisplayCampaign, GetCampaign, GetClient } from '../../services/Dragonroll';
import { ClearAll, CreateWindow } from '../../services/Windows';
const game = ref(null);
const in_game = InGameRef();
+const is_dm = ref(false);
function OpenCampaignPreview(){
CreateWindow('campaign_preview', {campaign: GetCampaign(), style: 'compact', hide_start: true, back: undefined, close: true});
@@ -22,9 +23,16 @@ function OpenDiceMenu(){
CreateWindow('dice_menu');
}
+function OpenMapButtons(){
+ CreateWindow('map_buttons');
+}
+
watch(game, () => {
if(game.value && in_game.value){
AddSound(game.value);
+
+ // Check if we are dm
+ is_dm.value = GetClient().is_dm;
}
});
@@ -40,6 +48,11 @@ watch(game, () => {