The best commit of humanity
This commit is contained in:
parent
569e165690
commit
5875b69089
@ -71,13 +71,14 @@
|
|||||||
--chat-background: var(--c-white);
|
--chat-background: var(--c-white);
|
||||||
|
|
||||||
--section-gap: 160px;
|
--section-gap: 160px;
|
||||||
|
--separator-color: #2e2e2e;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: dark) {
|
||||||
:root {
|
:root {
|
||||||
--window-background: var(--c-black-blurred);
|
--window-background: var(--c-black-blurred);
|
||||||
|
|
||||||
--color-handler: var(--c-black-semisoft);
|
--color-handler: #181818;
|
||||||
--color-background: var(--c-black);
|
--color-background: var(--c-black);
|
||||||
--color-background-semisoft: var(--c-black-semisoft);
|
--color-background-semisoft: var(--c-black-semisoft);
|
||||||
--color-background-soft: var(--c-black-soft);
|
--color-background-soft: var(--c-black-soft);
|
||||||
@ -98,8 +99,9 @@
|
|||||||
|
|
||||||
--color-chat-other: #1d1d1d;
|
--color-chat-other: #1d1d1d;
|
||||||
--color-roll-dice-chat: #665750;
|
--color-roll-dice-chat: #665750;
|
||||||
|
--separator-color: #363636;
|
||||||
|
|
||||||
--color-hover: var()
|
/* --color-hover: var() */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -144,3 +144,24 @@ button:active {
|
|||||||
margin-right: auto;
|
margin-right: auto;
|
||||||
display: block;
|
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;
|
||||||
|
}
|
191
client/src/services/Map.js
Normal file
191
client/src/services/Map.js
Normal file
@ -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,
|
||||||
|
};
|
@ -1,30 +1,16 @@
|
|||||||
import { reactive, ref } from 'vue'
|
import { reactive, ref } from 'vue'
|
||||||
import { Disconnect } from './Dragonroll';
|
import { Disconnect } from './Dragonroll';
|
||||||
|
|
||||||
const windows = {
|
const windows = ref([])
|
||||||
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 defValues = {
|
const defValues = {
|
||||||
'login': {
|
'login': {
|
||||||
id: 'login',
|
id: 'login',
|
||||||
title: 'Login'
|
title: 'Login',
|
||||||
},
|
},
|
||||||
'register': {
|
'register': {
|
||||||
id: 'register',
|
id: 'register',
|
||||||
title: 'Register'
|
title: 'Register',
|
||||||
},
|
},
|
||||||
'main_menu': {
|
'main_menu': {
|
||||||
id: 'main_menu',
|
id: 'main_menu',
|
||||||
@ -78,6 +64,16 @@ const defValues = {
|
|||||||
id: 'dice_menu',
|
id: 'dice_menu',
|
||||||
title: 'Dice roll',
|
title: 'Dice roll',
|
||||||
close: true
|
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})
|
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){
|
function ResetPosition(id, pos){
|
||||||
let win = GetWindowWithId(id);
|
let win = GetWindowWithId(id);
|
||||||
let data = {x: win.x, y: win.y};
|
let data = {x: win.x, y: win.y};
|
||||||
@ -181,22 +182,18 @@ function ResetPosition(id, pos){
|
|||||||
function CreateWindow(type, data = {}){
|
function CreateWindow(type, data = {}){
|
||||||
let finalData = {...{type}, ...defValues[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;
|
let contains = false;
|
||||||
for (let i = 0; i < windows[finalData.type].value.length; i++) {
|
for (let i = 0; i < windows.value.length; i++) {
|
||||||
if(windows[finalData.type].value[i].id == finalData.id){
|
if(windows.value[i].id == finalData.id){
|
||||||
contains = true;
|
contains = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!contains) {
|
if(!contains) {
|
||||||
windows[finalData.type].value.push(finalData);
|
windows.value.push(finalData);
|
||||||
// reload.value += 1;
|
// reload.value += 1;
|
||||||
|
|
||||||
|
console.log(windows.value);
|
||||||
setTimeout(() => SetOnTop(finalData.id), 0);
|
setTimeout(() => SetOnTop(finalData.id), 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,7 +209,7 @@ function CreateChildWindow(parentId, type, data = {}){
|
|||||||
|
|
||||||
function ClearAll(){
|
function ClearAll(){
|
||||||
Object.keys(windows).forEach((key) => {
|
Object.keys(windows).forEach((key) => {
|
||||||
windows[key].value = [];
|
windows.value = [];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,16 +224,14 @@ function ClearWindow(id){
|
|||||||
let win = GetWindowWithId(id);
|
let win = GetWindowWithId(id);
|
||||||
if(!win) return;
|
if(!win) return;
|
||||||
if(win.children) for(let i = 0; i < win.children.length; i++) ClearWindow(win.children[i]);
|
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;
|
// reload.value += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function GetWindowWithId(id){
|
function GetWindowWithId(id){
|
||||||
for(let key of Object.keys(windows)){
|
for(let i = 0; i < windows.value.length; i++){
|
||||||
for(let i = 0; i < windows[key].value.length; i++){
|
if(windows.value[i].id == id){
|
||||||
if(windows[key].value[i].id == id){
|
return windows.value[i];
|
||||||
return windows[key].value[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -268,6 +263,7 @@ export {
|
|||||||
CreateChildWindow,
|
CreateChildWindow,
|
||||||
GetWindowWithId,
|
GetWindowWithId,
|
||||||
SaveWindowPos,
|
SaveWindowPos,
|
||||||
|
GetPosition,
|
||||||
ClearWindow,
|
ClearWindow,
|
||||||
ClearAll
|
ClearAll
|
||||||
}
|
}
|
@ -4,11 +4,12 @@ import { InGameRef } from '../../services/Game';
|
|||||||
import IconButton from '../partials/game/IconButton.vue';
|
import IconButton from '../partials/game/IconButton.vue';
|
||||||
import { AddSound } from '../../services/Sound';
|
import { AddSound } from '../../services/Sound';
|
||||||
import TileMap from './TileMap.vue';
|
import TileMap from './TileMap.vue';
|
||||||
import { DisplayCampaign, GetCampaign } from '../../services/Dragonroll';
|
import { DisplayCampaign, GetCampaign, GetClient } from '../../services/Dragonroll';
|
||||||
import { ClearAll, CreateWindow } from '../../services/Windows';
|
import { ClearAll, CreateWindow } from '../../services/Windows';
|
||||||
|
|
||||||
const game = ref(null);
|
const game = ref(null);
|
||||||
const in_game = InGameRef();
|
const in_game = InGameRef();
|
||||||
|
const is_dm = ref(false);
|
||||||
|
|
||||||
function OpenCampaignPreview(){
|
function OpenCampaignPreview(){
|
||||||
CreateWindow('campaign_preview', {campaign: GetCampaign(), style: 'compact', hide_start: true, back: undefined, close: true});
|
CreateWindow('campaign_preview', {campaign: GetCampaign(), style: 'compact', hide_start: true, back: undefined, close: true});
|
||||||
@ -22,9 +23,16 @@ function OpenDiceMenu(){
|
|||||||
CreateWindow('dice_menu');
|
CreateWindow('dice_menu');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function OpenMapButtons(){
|
||||||
|
CreateWindow('map_buttons');
|
||||||
|
}
|
||||||
|
|
||||||
watch(game, () => {
|
watch(game, () => {
|
||||||
if(game.value && in_game.value){
|
if(game.value && in_game.value){
|
||||||
AddSound(game.value);
|
AddSound(game.value);
|
||||||
|
|
||||||
|
// Check if we are dm
|
||||||
|
is_dm.value = GetClient().is_dm;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -40,6 +48,11 @@ watch(game, () => {
|
|||||||
<IconButton icon="icons/iconoir/regular/cursor-pointer.svg"></IconButton>
|
<IconButton icon="icons/iconoir/regular/cursor-pointer.svg"></IconButton>
|
||||||
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dice-cup.svg" :action="OpenDiceMenu"></IconButton>
|
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dice-cup.svg" :action="OpenDiceMenu"></IconButton>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="vertical-button gm" v-if="is_dm">
|
||||||
|
<IconButton icon="icons/iconoir/regular/map.svg" :action="OpenMapButtons"></IconButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="horizontal-button">
|
<div class="horizontal-button">
|
||||||
<IconButton icon="icons/iconoir/regular/group.svg"></IconButton>
|
<IconButton icon="icons/iconoir/regular/group.svg"></IconButton>
|
||||||
<IconButton icon="icons/iconoir/regular/bookmark-book.svg"></IconButton>
|
<IconButton icon="icons/iconoir/regular/bookmark-book.svg"></IconButton>
|
||||||
@ -62,6 +75,10 @@ watch(game, () => {
|
|||||||
z-index: 1;
|
z-index: 1;
|
||||||
|
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
&.gm {
|
||||||
|
left: 48px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.horizontal-button {
|
.horizontal-button {
|
||||||
|
@ -1,132 +1,17 @@
|
|||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted } from 'vue';
|
import { onMounted, watch } from 'vue';
|
||||||
|
import { GetBackgroundColor, SetupTilemap } from '../../services/Map';
|
||||||
|
|
||||||
|
const backgroundColor = GetBackgroundColor();
|
||||||
let offsetX = 0;
|
|
||||||
let offsetY = 0;
|
|
||||||
let scale = 1;
|
|
||||||
|
|
||||||
let mouseX = 0;
|
|
||||||
let mouseY = 0;
|
|
||||||
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
console.log(scale);
|
|
||||||
draw();
|
|
||||||
}
|
|
||||||
|
|
||||||
function drawGrid(){
|
|
||||||
let canvas = document.getElementById('tilemap');
|
|
||||||
|
|
||||||
const width = canvas.clientWidth;
|
|
||||||
const height = canvas.clientHeight;
|
|
||||||
|
|
||||||
let ctx = canvas.getContext("2d");
|
|
||||||
|
|
||||||
let cellSize = 30;
|
|
||||||
|
|
||||||
ctx.strokeStyle = "#434343";
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
|
|
||||||
ctx.beginPath();
|
|
||||||
|
|
||||||
/* Vertical lines spanning the full width */
|
|
||||||
for (let x = (offsetX % cellSize) * scale; x <= width; x += cellSize * scale) {
|
|
||||||
ctx.moveTo(x, 0);
|
|
||||||
ctx.lineTo(x, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Horizontal lines spanning the full height */
|
|
||||||
for (let y = (offsetY % cellSize) * scale; y <= height; y += cellSize * scale) {
|
|
||||||
ctx.moveTo(0, y);
|
|
||||||
ctx.lineTo(width, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx.stroke();
|
|
||||||
|
|
||||||
ctx.strokeStyle = "red";
|
|
||||||
ctx.lineWidth = 1;
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.rect(toMapX(-10), toMapY(-10), 10 * scale, 10 * scale);
|
|
||||||
ctx.stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
drawGrid();
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
let tilemap = document.getElementById("tilemap");
|
SetupTilemap();
|
||||||
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) => {
|
watch(backgroundColor, () => {
|
||||||
mouseX = event.clientX;
|
let tilemap = document.getElementById('tilemap');
|
||||||
mouseY = event.clientY;
|
tilemap.style.backgroundColor = backgroundColor.value;
|
||||||
|
}, {deep: true});
|
||||||
if(!mouseDown) return;
|
|
||||||
offsetX = oldOffsetX + ((event.clientX - startX) * (1 / scale));
|
|
||||||
offsetY = oldOffsetY + ((event.clientY - startY) * (1 / scale));
|
|
||||||
|
|
||||||
draw();
|
|
||||||
// console.log("x: " + offsetX + ", y: " + offsetY);
|
|
||||||
});
|
|
||||||
|
|
||||||
tilemap.addEventListener("mouseup", () => mouseDown = false);
|
|
||||||
|
|
||||||
addEventListener("resize", draw)
|
|
||||||
|
|
||||||
offsetX = window.innerWidth / 2;
|
|
||||||
offsetY = window.innerHeight / 2;
|
|
||||||
|
|
||||||
draw();
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -17,43 +17,33 @@ import JoinCampaignWindow from '../windows/campaigns/JoinCampaignWindow.vue'
|
|||||||
import CampaignPreviewWindow from '@/views/windows/campaigns/CampaignPreviewWindow.vue'
|
import CampaignPreviewWindow from '@/views/windows/campaigns/CampaignPreviewWindow.vue'
|
||||||
import ChatWindow from '../windows/game/ChatWindow.vue'
|
import ChatWindow from '../windows/game/ChatWindow.vue'
|
||||||
import DiceWindow from '../windows/game/DiceWindow.vue'
|
import DiceWindow from '../windows/game/DiceWindow.vue'
|
||||||
|
import MapButtons from '../windows/dm/MapButtons.vue'
|
||||||
|
import EnvironmentWindow from '../windows/dm/EnvironmentWindow.vue'
|
||||||
|
|
||||||
// Gestionem ventanas
|
// Gestionem ventanas
|
||||||
const reload = ReloadRef();
|
const reload = ReloadRef();
|
||||||
const windows = Windows();
|
const windows = Windows();
|
||||||
|
|
||||||
// Win names
|
const WindowMap = {
|
||||||
const login = windows.login;
|
login: LoginWindow,
|
||||||
const register = windows.register;
|
main_menu: MainMenuWindow,
|
||||||
const test = windows.test;
|
register: RegisterWindow,
|
||||||
const main_menu = windows.main_menu;
|
edit_profile: EditProfileWindow,
|
||||||
const edit_profile = windows.edit_profile;
|
account_settings: AccountSettingsWindow,
|
||||||
const account_settings = windows.account_settings;
|
campaign_list: CampaignListWindow,
|
||||||
const db_window = windows.db_window;
|
new_campaign: NewCampaignWindow,
|
||||||
const campaign_list = windows.campaign_list;
|
join_campaign: JoinCampaignWindow,
|
||||||
const new_campaign = windows.new_campaign;
|
campaign_preview: CampaignPreviewWindow,
|
||||||
const join_campaign = windows.join_campaign;
|
chat: ChatWindow,
|
||||||
const campaign_preview = windows.campaign_preview;
|
dice_menu: DiceWindow,
|
||||||
const chat = windows.chat;
|
map_buttons: MapButtons,
|
||||||
const dice_menu = windows.dice_menu;
|
environment: EnvironmentWindow
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="window-container" :key="reload">
|
<div class="window-container" :key="reload">
|
||||||
<LoginWindow v-for="win in login" :key="win.id" :data="win"></LoginWindow>
|
<component v-for="win in windows" :is="WindowMap[win.type]" :key="win.id" :data="win"></component>
|
||||||
<RegisterWindow v-for="win in register" :key="win.id" :data="win"></RegisterWindow>
|
|
||||||
<ExampleWindow v-for="win in test" :key="win.id" :data="win"></ExampleWindow>
|
|
||||||
<MainMenuWindow v-for="win in main_menu" :key="win.id" :data="win"></MainMenuWindow>
|
|
||||||
<EditProfileWindow v-for="win in edit_profile" :key="win.id" :data="win"></EditProfileWindow>
|
|
||||||
<AccountSettingsWindow v-for="win in account_settings" :key="win.id" :data="win"></AccountSettingsWindow>
|
|
||||||
<DbWindow v-for="win in db_window" :key="win.id" :data="win"></DbWindow>
|
|
||||||
<CampaignListWindow v-for="win in campaign_list" :key="win.id" :data="win"></CampaignListWindow>
|
|
||||||
<NewCampaignWindow v-for="win in new_campaign" :key="win.id" :data="win"></NewCampaignWindow>
|
|
||||||
<JoinCampaignWindow v-for="win in join_campaign" :key="win.id" :data="win"></JoinCampaignWindow>
|
|
||||||
<CampaignPreviewWindow v-for="win in campaign_preview" :key="win.id" :data="win"></CampaignPreviewWindow>
|
|
||||||
<ChatWindow v-for="win in chat" :key="win.id" :data="win"></ChatWindow>
|
|
||||||
<DiceWindow v-for="win in dice_menu" :key="win.id" :data="win"></DiceWindow>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -92,7 +92,7 @@ watch(chat, () => {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
max-height: 580px;
|
max-height: 620px;
|
||||||
|
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
48
client/src/views/partials/parameters/ColorValue.vue
Normal file
48
client/src/views/partials/parameters/ColorValue.vue
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
<script setup>
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
|
||||||
|
const color = ref("");
|
||||||
|
const colorValue = ref(null);
|
||||||
|
const colorPicker = ref(null);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
colorValue.value.addEventListener('click', () => {
|
||||||
|
console.log("Click");
|
||||||
|
colorPicker.value.click();
|
||||||
|
})
|
||||||
|
|
||||||
|
colorPicker.value.addEventListener('input', (event) => {
|
||||||
|
let newColor = event.target.value;
|
||||||
|
colorValue.value.classList.remove('unselected');
|
||||||
|
colorValue.value.style.backgroundColor = newColor;
|
||||||
|
color.value = newColor;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
let GetColor = () => color;
|
||||||
|
|
||||||
|
defineExpose({ GetColor });
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<input type="color" id="colorPicker" ref="colorPicker">
|
||||||
|
<div class="color-value unselected" ref="colorValue"></div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
#colorPicker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color-value {
|
||||||
|
width: 30px;
|
||||||
|
height: 20px;
|
||||||
|
|
||||||
|
&.unselected {
|
||||||
|
background-image: linear-gradient(45deg, #808080 25%, transparent 25%), linear-gradient(-45deg, #808080 25%, transparent 25%), linear-gradient(45deg, transparent 75%, #808080 75%), linear-gradient(-45deg, transparent 75%, #808080 75%);
|
||||||
|
background-size: 10px 10px;
|
||||||
|
background-position: 0 0, 0 5px, 5px -5px, -5px 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
</style>
|
59
client/src/views/windows/dm/EnvironmentWindow.vue
Normal file
59
client/src/views/windows/dm/EnvironmentWindow.vue
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
<script setup>
|
||||||
|
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||||
|
|
||||||
|
import { onMounted, onUpdated, ref, watch } from 'vue';
|
||||||
|
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
||||||
|
import IconButton from '@/views/partials/game/IconButton.vue'
|
||||||
|
import ColorValue from '../../partials/parameters/ColorValue.vue';
|
||||||
|
import { GetBackgroundColor } from '../../../services/Map';
|
||||||
|
|
||||||
|
const props = defineProps(['data']);
|
||||||
|
const data = props.data;
|
||||||
|
|
||||||
|
const handle = ref(null);
|
||||||
|
const mapUploader = ref(null);
|
||||||
|
|
||||||
|
const env_background = ref(null);
|
||||||
|
|
||||||
|
let id = data.id;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
SetupHandle(id, handle);
|
||||||
|
SetSize(id, {x: 200, y: 300});
|
||||||
|
ResetPosition(id, {x: data.x, y: data.y});
|
||||||
|
|
||||||
|
console.log(env_background.value.GetColor());
|
||||||
|
watch(env_background.value.GetColor(), () => {
|
||||||
|
GetBackgroundColor().value = env_background.value.GetColor().value; // XD
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function UploadButton(){
|
||||||
|
mapUploader.value.click();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="window-wrapper" :id="'window-wrapper-' + id">
|
||||||
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||||
|
|
||||||
|
<div class="parameters">
|
||||||
|
<div class="param-element">
|
||||||
|
<div class="param-text">Background color: </div>
|
||||||
|
<div class="param-value"><ColorValue ref="env_background"></ColorValue></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
|
||||||
|
.window-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
</style>
|
107
client/src/views/windows/dm/MapButtons.vue
Normal file
107
client/src/views/windows/dm/MapButtons.vue
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
<script setup>
|
||||||
|
import WindowHandle from '@/views/partials/WindowHandle.vue';
|
||||||
|
|
||||||
|
import { onMounted, onUpdated, ref } from 'vue';
|
||||||
|
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
|
||||||
|
import IconButton from '@/views/partials/game/IconButton.vue'
|
||||||
|
import { ImportDD2VTT } from '../../../services/Map';
|
||||||
|
import { CreateChildWindow, GetPosition } from '../../../services/Windows';
|
||||||
|
|
||||||
|
const props = defineProps(['data']);
|
||||||
|
const data = props.data;
|
||||||
|
|
||||||
|
const handle = ref(null);
|
||||||
|
const mapUploader = ref(null);
|
||||||
|
|
||||||
|
let id = data.id;
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
SetupHandle(id, handle);
|
||||||
|
SetSize(id, {x: 40, y: 500});
|
||||||
|
ResetPosition(id, {x: 10, y: 200});
|
||||||
|
|
||||||
|
mapUploader.value.addEventListener('change', (event) => {
|
||||||
|
let file = event.target.files[0];
|
||||||
|
let reader = new FileReader();
|
||||||
|
reader.addEventListener('load', (event) => {
|
||||||
|
ImportDD2VTT(JSON.parse(event.target.result));
|
||||||
|
});
|
||||||
|
|
||||||
|
reader.readAsText(file);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
function UploadButton(){
|
||||||
|
mapUploader.value.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditEnvironment(){
|
||||||
|
let winPos = GetPosition(id);
|
||||||
|
CreateChildWindow(id, 'environment', {x: winPos.x + 50, y: winPos.y});
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<form id="send-map-form" enctype="multipart/form-data">
|
||||||
|
<input name="file" type="file" accept=".dd2vtt" ref="mapUploader">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="window-wrapper" :id="'window-wrapper-' + id">
|
||||||
|
<WindowHandle :window="id" ref="handle"></WindowHandle>
|
||||||
|
|
||||||
|
<div class="vertical-button">
|
||||||
|
<IconButton icon="icons/iconoir/regular/upload.svg" :action="UploadButton"></IconButton>
|
||||||
|
<hr>
|
||||||
|
<IconButton icon="icons/iconoir/regular/square-3d-three-points.svg" :action="UploadButton"></IconButton>
|
||||||
|
<IconButton icon="icons/iconoir/regular/orthogonal-view.svg" :action="UploadButton"></IconButton>
|
||||||
|
<hr>
|
||||||
|
<IconButton icon="icons/iconoir/regular/sun-light.svg" :action="EditEnvironment"></IconButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
#send-map-form {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.window-wrapper {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 26px;
|
||||||
|
left: 2px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
z-index: 1;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&.gm {
|
||||||
|
left: 48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr::before {
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
hr {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
width: 30px;
|
||||||
|
margin-top: 1px;
|
||||||
|
margin-bottom: 1px;
|
||||||
|
background-color: var(--separator-color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -15,7 +15,7 @@ let id = data.id;
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
SetSize(id, {x: 400, y: 750});
|
SetSize(id, {x: 400, y: 750});
|
||||||
ResetPosition(id, "center");
|
ResetPosition(id, {x: window.innerWidth - 420, y: 80});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ function ThrowCustomDice(){
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
SetupHandle(id, handle);
|
SetupHandle(id, handle);
|
||||||
SetSize(id, {x: 300, y: 210});
|
SetSize(id, {x: 300, y: 210});
|
||||||
ResetPosition(id, "center");
|
ResetPosition(id, {x: 100, y: 150});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user