Mas cosas

This commit is contained in:
BinarySandia04 2024-08-06 23:02:18 +02:00
parent e2cf465862
commit 569e165690
20 changed files with 652 additions and 21 deletions

View File

@ -11,6 +11,7 @@
"@kangc/v-md-editor": "^2.3.17",
"axios": "^1.5.1",
"babel-plugin-prismjs": "^2.1.0",
"dice-notation-js": "^1.0.3",
"ef-infinite-canvas": "^0.6.6",
"form-data": "^4.0.0",
"jquery": "^3.7.1",
@ -5102,6 +5103,12 @@
"dev": true,
"license": "MIT"
},
"node_modules/dice-notation-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/dice-notation-js/-/dice-notation-js-1.0.3.tgz",
"integrity": "sha512-K02a/w3kjRp4QPYE3+qlXnQRVw9n00IIJHYtrxAryIIC112SP36YKo2Z9CR/f+ZKzj+YKJmCeTKnMIc4+crG5g==",
"license": "MIT"
},
"node_modules/dir-glob": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.2.2.tgz",

View File

@ -12,6 +12,7 @@
"@kangc/v-md-editor": "^2.3.17",
"axios": "^1.5.1",
"babel-plugin-prismjs": "^2.1.0",
"dice-notation-js": "^1.0.3",
"ef-infinite-canvas": "^0.6.6",
"form-data": "^4.0.0",
"jquery": "^3.7.1",

View File

@ -0,0 +1,7 @@
<svg version="1.2" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
<title>perspective-dice-six-svg</title>
<style>
.s0 { fill: #000000 }
</style>
<path id="Layer" fill-rule="evenodd" class="s0" d="m272.8 46.9l152.8 88.4c9.6 5.5 9.6 14.3 0 19.8l-152.8 88.4c-9.5 5.5-24.7 5.5-34.2 0l-152.8-88.4c-9.6-5.5-9.6-14.3 0-19.8l152.8-88.4c4.7-2.8 10.9-4.1 17.1-4.1 6.2 0 12.4 1.3 17.1 4.1zm-44.8 58.3q-4.8 1.9-9.1 4.5-13.4 8-10.3 19.4 3 11.2 21.7 22.9 18.3 11.5 34.9 13.8 16.5 2.2 28.5-5 10.9-6.5 10-14.9-0.8-8.5-13-16.1-11-6.9-23.6-7.6-12.5-0.8-22 4.8-3.7 2.3-5.7 5-1.9 2.7-2.1 5.8-8.9-6.3-9.8-11.7-0.9-5.4 6.2-9.7 3.3-1.9 7.9-3.3 4.5-1.4 10.7-2.4l-14-8.7q-5.5 1.3-10.3 3.2zm34.2 29.1q0.4 0 0.7 0 0.3 0.1 0.6 0.1 0.4 0.1 0.7 0.1 5.4 0.8 12 4.9 6.7 4.2 7.9 7.5 1.2 3.3-3 5.9-4.1 2.5-9.5 1.7-5.4-0.9-12.1-5-6.6-4.2-7.8-7.5-1.3-3.3 2.9-5.8 3.1-1.9 7-1.9 0.3 0 0.6 0zm183.9 49.8v157.7c0 11.1-7.6 24.2-17.2 29.7l-146.9 84.9c-9.6 5.5-17.2 1.1-17.2-9.9v-157.7c0-11.1 7.6-24.2 17.2-29.7l146.9-84.9c2.7-1.5 5-2.3 7-2.4 4.9-0.2 7.7 4.3 10.2 12.3zm-363-9.9l146.9 84.9c9.6 5.5 17.2 18.6 17.2 29.7v157.7c0 11-7.6 15.4-17.2 9.9l-146.9-84.9c-9.6-5.5-17.2-18.6-17.2-29.7v-157.7c0.2-6.5 4-11.8 10.2-11.8 2.1 0 4.4 0.6 7 1.9zm45.4 136.4q4.6 0.4 8.5 1.6 1 0.3 2 0.7 0.9 0.3 1.9 0.8 0.9 0.4 1.8 0.9 0.9 0.4 1.8 1 5.9 3.5 9.3 9.1 3.5 5.7 3.5 12 0 6.2-3.5 7.8-3.4 1.6-9.3-2-4.1-2.4-8.7-7.1-4.6-4.6-9.8-11.4v16.1q5.2 5.7 10.4 10.2 5.3 4.5 10.7 7.7 12.4 7.5 19.4 4.4 7-3.1 7-15.9 0-13-6.4-24.1-6.4-11.1-18-18-2-1.3-3.9-2-0.4-0.2-0.9-0.4-0.5-0.2-0.9-0.3-0.5-0.2-1-0.3-0.4-0.2-0.9-0.3v-12.3l27.5 16.5v-15l-40.5-24.3zm236.2-32.8l-22.7 61.4v17.7l25.2-15.1v14.6l13.8-8.3v-14.6l8.1-4.8v-15l-8.1 4.8v-50.5zm2.5 49.1l-16.1 9.6 16.1-43.2z"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
client/public/img/d20.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -22,7 +22,7 @@
--c-black-muter: #585858;
--c-black-blurred: #222222cc;
--c-black-blurred: #222222;
--c-indigo: #2c3e50;
@ -96,6 +96,9 @@
--chat-background: var(--c-blacker);
--text-disabled: #7e7e7e;
--color-chat-other: #1d1d1d;
--color-roll-dice-chat: #665750;
--color-hover: var()
}
}

View File

@ -67,6 +67,13 @@ a {
background-color: var(--c-button-green-hover);
}
.btn-red {
background-color: var(--c-button-red);
}
.btn-red:hover {
background-color: var(--c-button-red-hover);
}
hr {
border: 0;
height: 1px;

View File

@ -4,6 +4,7 @@ import { io } from "socket.io-client";
import Api from '@/services/Api'
import { backendUrl } from './BackendURL';
import { GetUser } from './User';
import { ExitGame } from './Game';
let emitter;
@ -25,7 +26,24 @@ let GetPlayerList = () => { return players; };
let GetCampaign = () => { return currentCampaign; };
let GetClient = () => { return currentPlayer; };
let chatMessageId = 0;
const chat = ref([
/* {
id: 1,
author: "66ae8aea3e78bb669e25010d",
chunks: [
{
id: 1,
type: "text",
content: "Hola test"
}
]
} */
]);
let GetChatRef = () => chat;
socket.on('update-players', data => {
console.log(data);
players.value = [];
Object.keys(data).forEach((key) => {
players.value.push(data[key]);
@ -33,22 +51,60 @@ socket.on('update-players', data => {
});
})
function DisplayCampaign(data){
socket.on('message', (data) => {
// Add new chat message, ?
if(chat.value.length > 0) if(chat.value[chat.value.length - 1].author == data.author){
chat.value[chat.value.length - 1].chunkSize += 1;
chat.value[chat.value.length - 1].chunks.push({
id: chat.value[chat.value.length - 1].chunkSize,
type: data.type ? data.type : 'text',
content: data.content
});
return;
}
chatMessageId += 1;
chat.value.push({
id: chatMessageId,
author: data.author,
chunkSize: 1,
chunks: [
{
id: 1,
type: data.type ? data.type : 'text',
content: data.content
}
]
});
});
function SendMessage(data){
socket.emit('message', data);
}
function DisplayCampaign(data = currentCampaign){
ClearAll();
CreateWindow('campaign_preview', {campaign: data});
}
function ConnectToCampaign(campaign){
currentCampaign = campaign;
chat.value = [];
socket.emit('enter', GetUser(), currentCampaign._id);
}
function Disconnect(){
socket.emit('exit');
ExitGame();
currentCampaign = null;
currentPlayer = null;
chat.value = [];
}
function GetPlayer(player_campaign){
console.log(players.value);
let index = players.value.findIndex((p) => {return p._id == player_campaign});
if(index != -1) return players.value[index];
}
@ -66,4 +122,7 @@ export {
GetClient,
GetPlayerList,
GetPlayer,
GetChatRef,
SendMessage
};

View File

@ -12,7 +12,9 @@ const windows = {
campaign_list: ref([]),
new_campaign: ref([]),
join_campaign: ref([]),
campaign_preview: ref([])
campaign_preview: ref([]),
chat: ref([]),
dice_menu: ref([]),
};
const defValues = {
@ -66,6 +68,16 @@ const defValues = {
ClearWindow('campaign_preview');
CreateWindow('campaign_list');
}
},
'chat': {
id: 'chat',
title: 'Chat',
close: true
},
'dice_menu': {
id: 'dice_menu',
title: 'Dice roll',
close: true
}
}

View File

@ -4,12 +4,26 @@ 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 { ClearAll, CreateWindow } from '../../services/Windows';
const game = ref(null);
const in_game = InGameRef();
function OpenCampaignPreview(){
CreateWindow('campaign_preview', {campaign: GetCampaign(), style: 'compact', hide_start: true, back: undefined, close: true});
}
function OpenChat(){
CreateWindow('chat');
}
function OpenDiceMenu(){
CreateWindow('dice_menu');
}
watch(game, () => {
if(game){
if(game.value && in_game.value){
AddSound(game.value);
}
});
@ -22,12 +36,14 @@ watch(game, () => {
<!-- Aquests dos son absolute -->
<div class="vertical-button">
<IconButton icon="icons/iconoir/regular/menu.svg"></IconButton>
<IconButton icon="icons/iconoir/regular/menu.svg" :action="OpenCampaignPreview"></IconButton>
<IconButton icon="icons/iconoir/regular/cursor-pointer.svg"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dice-cup.svg"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dice-cup.svg" :action="OpenDiceMenu"></IconButton>
</div>
<div class="horizontal-button">
<IconButton icon="icons/iconoir/regular/group.svg"></IconButton>
<IconButton icon="icons/iconoir/regular/bookmark-book.svg"></IconButton>
<IconButton icon="icons/iconoir/regular/chat-bubble.svg" :action="OpenChat"></IconButton>
</div>
<!-- Tilemap -->
@ -44,5 +60,18 @@ watch(game, () => {
display: flex;
flex-direction: column;
z-index: 1;
user-select: none;
}
.horizontal-button {
position: absolute;
top: 10px;
right: 10px;
display: flex;
flex-direction: row;
z-index: 1;
user-select: none;
}
</style>

View File

@ -115,12 +115,16 @@ onMounted(() => {
offsetY = oldOffsetY + ((event.clientY - startY) * (1 / scale));
draw();
console.log("x: " + offsetX + ", y: " + offsetY);
// console.log("x: " + offsetX + ", y: " + offsetY);
});
tilemap.addEventListener("mouseup", () => mouseDown = false);
addEventListener("resize", draw)
offsetX = window.innerWidth / 2;
offsetY = window.innerHeight / 2;
draw();
});

View File

@ -15,6 +15,8 @@ import CampaignListWindow from '../windows/campaigns/CampaignListWindow.vue'
import NewCampaignWindow from '../windows/campaigns/NewCampaignWindow.vue'
import JoinCampaignWindow from '../windows/campaigns/JoinCampaignWindow.vue'
import CampaignPreviewWindow from '@/views/windows/campaigns/CampaignPreviewWindow.vue'
import ChatWindow from '../windows/game/ChatWindow.vue'
import DiceWindow from '../windows/game/DiceWindow.vue'
// Gestionem ventanas
const reload = ReloadRef();
@ -32,6 +34,8 @@ const campaign_list = windows.campaign_list;
const new_campaign = windows.new_campaign;
const join_campaign = windows.join_campaign;
const campaign_preview = windows.campaign_preview;
const chat = windows.chat;
const dice_menu = windows.dice_menu;
</script>
@ -48,6 +52,8 @@ const campaign_preview = windows.campaign_preview;
<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>
</template>
@ -57,7 +63,7 @@ const campaign_preview = windows.campaign_preview;
.window-wrapper {
background-color: var(--window-background);
backdrop-filter: blur(10px);
/* backdrop-filter: blur(10px); */
position: fixed;

View File

@ -0,0 +1,146 @@
<script setup>
import IconButton from '@/views/partials/game/IconButton.vue';
import { onMounted, ref, watch } from 'vue';
import MessageComponent from './MessageComponent.vue';
import { GetChatRef, GetClient, SendMessage } from '../../services/Dragonroll';
const textInput = ref(null);
const chat = GetChatRef();
const messageContainer = ref(null);
function Send(message){
SendMessage({
content: {
text: message
},
author: GetClient()._id
});
}
onMounted(() => {
textInput.value.addEventListener('input', (event) => {
// textInput.value.style.height = "1px";
textInput.value.style.height = (textInput.value.scrollHeight)+"px";
})
textInput.value.addEventListener("keypress", (event) => {
if(event.shiftKey) return;
if (event.key === "Enter") {
event.preventDefault();
Send(textInput.value.value);
textInput.value.value = "";
textInput.value.style.height = "1px";
textInput.value.style.height = (textInput.value.scrollHeight)+"px";
}
})
});
watch(chat, () => {
if(chat.value.length > 0) if(chat.value[chat.value.length - 1].author == GetClient()._id){
setTimeout(() => {
messageContainer.value.scrollTop = messageContainer.value.scrollHeight;
console.log(messageContainer.value.scrollHeight)
}, 0);
}
}, {deep: true})
</script>
<template>
<div class="chat-container">
<div class="message-container" ref="messageContainer">
<MessageComponent v-for="message in chat" :key="message._id" :message="message"></MessageComponent>
</div>
<div class="chat-input-container">
<textarea ref="textInput" class="chat-input"></textarea>
<div class="chat-input-actions">
<div class="chat-input-actions-left">
</div>
<div class="chat-input-actions-right">
<IconButton icon="icons/iconoir/regular/send.svg"></IconButton>
</div>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
.chat-container {
display: flex;
height: 720px;
width: 100%;
flex-direction: column;
h2 {
font-family: MrEavesRemake;
margin-left: 10px;
margin-top: 5px;
}
}
.message-container {
flex-grow: 1;
display: flex;
flex-direction: column;
overflow-y: auto;
max-height: 580px;
margin-bottom: 10px;
}
.chat-input-container {
position: sticky;
bottom: 0px;
width: 100%;
}
.chat-input {
background-color: var(--color-background-softer);
border: none;
padding: 12px;
border-radius: 6px;
color: var(--color-text);
transition: 300ms background-color;
width: calc(100% - 20px);
margin-left: 10px;
margin-right: 10px;
min-height: 30px;
height: 41px;
max-height: 100px;
resize: none;
&:focus {
outline: none;
background-color: var(--color-background-softest);
}
}
.chat-input-actions {
display: flex;
flex-direction: column;
margin-bottom: 8px;
margin-left: 10px;
margin-right: 10px;
margin-top: 8px;
}
.chat-input-actions-left {
margin-right: auto;
}
.chat-input-actions-right {
margin-left: auto;
}
</style>

View File

@ -0,0 +1,61 @@
<script setup>
import { onMounted, ref } from 'vue';
const text = ref("");
const roll = ref("");
const props = defineProps(['data']);
const data = props.data;
onMounted(() => {
if(data.type == "dice-roll"){
text.value = data.content.throw;
roll.value = data.content.roll;
} else {
text.value = data.content.text;
}
});
</script>
<template>
<div class="msg-chunk">
<span v-if="data.type == 'text'">{{ text }}</span>
<div v-if="data.type == 'dice-roll'" class="dice-roll-container">
<span class="roll-title">Rolled {{ text }}</span>
<span class="roll-result">{{ roll }}</span>
<img class="roll-bg" src="/img/d20.png">
</div>
</div>
</template>
<style scoped lang="scss">
.dice-roll-container {
display: flex;
flex-direction: column;
width: 300px;
padding-bottom: 10px;
}
.roll-title {
font-weight: bold;
}
.roll-result {
font-size: 48px;
font-weight: bold;
font-family: MrEavesRemake;
text-align: center;
margin-bottom: -75px;
}
.roll-bg {
filter: invert(0.9);
opacity: 0.1;
width: 75px;
position: relative;
left: 112px;
top: 0px;
}
</style>

View File

@ -0,0 +1,65 @@
<script setup>
import { onMounted, ref } from 'vue';
import MessageChunk from './MessageChunk.vue';
import { GetPlayer } from '../../services/Dragonroll';
import { backendUrl } from '../../services/BackendURL';
const props = defineProps(['message']);
const message = props.message;
const avatar = ref(null);
const title = ref("");
const chunks = ref([]);
onMounted(() => {
let sender = GetPlayer(message.author);
if(sender.user.image) avatar.value.src = backendUrl + "public/" + sender.user.image;
title.value = sender.user.username;
chunks.value = message.chunks;
});
</script>
<template>
<div class="msg-parent-container rcv">
<img class="user-icon" src="img/def-avatar.jpg" ref="avatar" draggable="false">
<div class="content-container">
<div class="msg-title">
{{ title }}
</div>
<MessageChunk v-for="chunk in chunks" :id="chunk.id" :data="chunk"></MessageChunk>
</div>
</div>
</template>
<style scoped lang="scss">
.msg-title {
font-weight: bold;
}
.msg-parent-container {
width: 100%;
background-color: var(--color-chat-other);
display: flex;
margin-top: 2px;
padding-left: 10px;
}
.content-container {
max-width: 75%;
padding: 7px 15px;
margin-bottom: 7px;
text-align: left;
}
.user-icon {
margin-top: 9px;
width: 32px;
height: 32px;
}
</style>

View File

@ -1,13 +1,16 @@
<script setup>
const props = defineProps(['icon']);
const props = defineProps(['icon', 'action','size']);
let icon = props.icon;
let action = props.action;
let size = props.size;
</script>
<template>
<div class="icon-button sound-click">
<img class="icon" :src="icon">
<div class="icon-button sound-click" :class="size" v-on:click.prevent="action">
<img class="icon" draggable="false" :src="icon" :class="size">
</div>
</template>
@ -16,6 +19,12 @@ let icon = props.icon;
.icon-button {
height: 32px;
width: 32px;
&.big {
height: 42px;
width: 42px;
}
background-color: var(--color-background-soft);
border-radius: 6px;
display: flex;
@ -34,4 +43,9 @@ let icon = props.icon;
height: 24px;
width: 24px;
}
.big {
height: 38px;
width: 38px;
}
</style>

View File

@ -4,23 +4,39 @@ import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Win
import WindowHandle from '@/views/partials/WindowHandle.vue';
import PlayerList from '../../partials/PlayerList.vue';
import { DisplayToast, GetCampaign, GetClient } from '../../../services/Dragonroll';
import { Disconnect, DisplayToast, GetCampaign, GetClient } from '../../../services/Dragonroll';
import CampaignBookList from '../../partials/books/CampaignBookList.vue';
import { ClearWindow } from '../../../services/Windows';
import { ClearAll, ClearWindow, CreateWindow } from '../../../services/Windows';
import { LaunchGame } from '../../../services/Game';
import { AddSound } from '../../../services/Sound';
import ChatComponent from '../../partials/ChatComponent.vue';
const handle = ref(null);
const props = defineProps(['data']);
const data = props.data;
const hide_start = ref(false);
const hide_chat = ref(false);
const container = ref(null);
let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
if(data.style == 'compact') {
SetSize(id, {x: 800, y: 750});
hide_chat.value = true;
} else {
SetSize(id, {x: 1200, y: 750});
}
ResetPosition(id, "center");
console.log(data);
hide_start.value = data.hide_start;
AddSound(container.value)
});
function CopyCode(){
@ -33,6 +49,12 @@ function Launch(){
LaunchGame();
}
function Exit(){
Disconnect();
ClearAll();
CreateWindow('campaign_list');
}
</script>
@ -43,7 +65,7 @@ function Launch(){
<!-- Body
<h1>{{ data.campaign.name }}</h1> -->
<div class="campaign-preview-container">
<div class="campaign-preview-container" :class="hide_chat ? 'campaign-preview-compact' : ''" ref="container">
<div class="campaign-preview-column left">
<h2>Players</h2>
<PlayerList :campaign="data.campaign"></PlayerList>
@ -61,11 +83,12 @@ function Launch(){
</div>
</div>
<div class="buttons-row">
<button class="btn-primary button-row sound-click btn-green" v-on:click.prevent="Launch">Launch game</button>
<button class="btn-primary button-row sound-click btn-green" v-if="!hide_start" v-on:click.prevent="Launch">Launch game</button>
<button class="btn-primary button-row sound-click btn-red" v-if="hide_start" v-on:click.prevent="Exit">Exit game</button>
</div>
</div>
<div class="campaign-preview-column right">
<h2>Chat</h2>
<div v-if="!hide_chat" class="campaign-preview-column right">
<ChatComponent></ChatComponent>
</div>
</div>
@ -115,6 +138,10 @@ function Launch(){
display: grid;
grid-template-columns: 3fr 5fr 4fr;
&.campaign-preview-compact {
grid-template-columns: 2fr 3fr;
}
}
.campaign-preview-column {

View File

@ -0,0 +1,38 @@
<script setup>
import WindowHandle from '@/views/partials/WindowHandle.vue';
import { onMounted, onUpdated, ref } from 'vue';
import { SetupHandle, SetSize, SetPosition, ResetPosition } from '@/services/Windows';
import ChatComponent from '../../partials/ChatComponent.vue';
const props = defineProps(['data']);
const data = props.data;
const handle = ref(null);
let id = data.id;
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {x: 400, y: 750});
ResetPosition(id, "center");
});
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<ChatComponent></ChatComponent>
</div>
</template>
<style scoped>
.window-wrapper {
display: flex;
align-items: center;
}
</style>

View File

@ -0,0 +1,140 @@
<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 Dice from 'dice-notation-js'
import { GetClient, SendMessage } from '../../../services/Dragonroll';
const props = defineProps(['data']);
const data = props.data;
const handle = ref(null);
const diceResult = ref("");
const diceField = ref(null);
let id = data.id;
let ThrowD4 = () => { ThrowDice("d4") };
let ThrowD6 = () => { ThrowDice("d6") };
let ThrowD8 = () => { ThrowDice("d8") };
let ThrowD10 = () => { ThrowDice("d10") };
let ThrowD12 = () => { ThrowDice("d12") };
let ThrowD20 = () => { ThrowDice("d20") };
function comp (s, m, n, f, a) {
m = parseInt( m );
if( isNaN( m ) ) m = 1;
n = parseInt( n );
if( isNaN( n ) ) n = 1;
f = parseInt( f );
a = typeof(a) == 'string' ? parseInt( a.replace(/\s/g, '') ) : 0;
if( isNaN( a ) ) a = 0;
var r = 0;
for( var i=0; i<n; i++ )
r += Math.floor( Math.random() * f ) + 1;
return r * m + a;
};
function parse( de ) {
return comp.apply( this, de.match(/(?:(\d+)\s*\*\s*)?(\d*)d(\d+)(?:\s*([\+\-]\s*\d+))?/i) );
}
function ThrowDice(expr){
// let result = Dice.detailed(expr);
diceField.value.value = expr;
let result = parse(expr);
let audios = ['/sounds/roll1.wav', '/sounds/roll2.wav']
const audio = new Audio(audios[Math.floor(Math.random() * audios.length)]);
audio.type = "audio/wav"
audio.play();
console.log(result)
diceResult.value = result;
SendMessage({
content: {
roll: result,
throw: expr
},
author: GetClient()._id,
type: 'dice-roll'
})
}
function ThrowCustomDice(){
ThrowDice(diceField.value.value);
}
onMounted(() => {
SetupHandle(id, handle);
SetSize(id, {x: 300, y: 210});
ResetPosition(id, "center");
});
</script>
<template>
<div class="window-wrapper" :id="'window-wrapper-' + id">
<WindowHandle :window="id" ref="handle"></WindowHandle>
<div class="horizontal-dice">
<IconButton icon="icons/game-icons/000000/skoll/d4.svg" :action="ThrowD4" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/perspective-dice-six-svg.svg" :action="ThrowD6" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/dice-eight-faces-eight.svg" :action="ThrowD8" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d10.svg" :action="ThrowD10" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/skoll/d12.svg" :action="ThrowD12" size="big"></IconButton>
<IconButton icon="icons/game-icons/000000/delapouite/dice-twenty-faces-twenty.svg" :action="ThrowD20" size="big"></IconButton>
</div>
<div class="custom-dice">
<input type="text" ref="diceField">
<IconButton icon="icons/game-icons/000000/delapouite/rolling-dices.svg" size="big" :action="ThrowCustomDice"></IconButton>
</div>
<div class="roll-result">{{ diceResult }}</div>
</div>
</template>
<style scoped>
.window-wrapper {
display: flex;
align-items: center;
user-select: none;
}
.horizontal-dice {
display: flex;
flex-direction: row;
z-index: 1;
user-select: none;
}
.custom-dice {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
}
input[type=text] {
height: 32px;
padding: 6px;
border-radius: 6px;
margin-right: 6px;
text-align: center;
}
.roll-result {
font-size: 48px;
font-weight: bold;
font-family: MrEavesRemake;
}
</style>

View File

@ -33,7 +33,8 @@ module.exports = io => {
socket.campaign = campaignId;
if(!sessions[campaignId]) sessions[campaignId] = {
players: await GetOfflinePlayers(campaignId)
players: await GetOfflinePlayers(campaignId),
chat: []
};
@ -55,5 +56,9 @@ module.exports = io => {
console.log(socket.user.username + " ha salido!")
});
socket.on('message', (data) => {
io.to(socket.campaign).emit('message', data);
})
});
}