Compare commits
40 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ebdc1b5e5c | ||
|
|
07a3bdd837 | ||
|
|
08fdde939a | ||
|
|
484b7a0b7f | ||
|
|
bf8c5c0076 | ||
|
|
e229abc3ee | ||
|
|
51119f42ea | ||
|
|
42e4f8f0d8 | ||
|
|
c3ee0a76aa | ||
|
|
2264d018c2 | ||
|
|
8fa32838d8 | ||
|
|
1552ae6fe8 | ||
|
|
cc9bcf4770 | ||
|
|
7d4fd1e8b1 | ||
|
|
780e06d581 | ||
|
|
64983ca0cb | ||
|
|
dd534488da | ||
|
|
7e2796316e | ||
|
|
7fa5352459 | ||
|
|
c31cea4c64 | ||
|
|
f994e64fc7 | ||
|
|
f0c1b0e1e0 | ||
|
|
cc5dc9ab63 | ||
|
|
64fd6cb132 | ||
|
|
888b089e7b | ||
|
|
959b9c9e4e | ||
|
|
afaf1c9799 | ||
|
|
2947c54eb8 | ||
|
|
561e3f4bd0 | ||
|
|
33f27047b1 | ||
|
|
7c532f5155 | ||
|
|
e62e82795b | ||
|
|
91e07e79c5 | ||
|
|
fc471ce400 | ||
|
|
1370544f03 | ||
|
|
7bd2084209 | ||
|
|
0ae6336f52 | ||
|
|
8f1a5271dd | ||
|
|
199f9b2d3b | ||
|
|
f178245152 |
479
MaterialDeck.js
@@ -1,26 +1,37 @@
|
|||||||
import {registerSettings} from "./src/settings.js";
|
import {registerSettings} from "./src/settings.js";
|
||||||
import {StreamDeck} from "./src/streamDeck.js";
|
import {StreamDeck} from "./src/streamDeck.js";
|
||||||
import {TokenControl} from "./src/token.js";
|
import {TokenControl} from "./src/token.js";
|
||||||
import {Move} from "./src/move.js";
|
|
||||||
import {MacroControl} from "./src/macro.js";
|
import {MacroControl} from "./src/macro.js";
|
||||||
import {CombatTracker} from "./src/combattracker.js";
|
import {CombatTracker} from "./src/combattracker.js";
|
||||||
import {PlaylistControl} from "./src/playlist.js";
|
import {PlaylistControl} from "./src/playlist.js";
|
||||||
import {SoundboardControl} from "./src/soundboard.js";
|
import {SoundboardControl} from "./src/soundboard.js";
|
||||||
import {OtherControls} from "./src/othercontrols.js";
|
import {OtherControls} from "./src/othercontrols.js";
|
||||||
|
import {ExternalModules} from "./src/external.js";
|
||||||
|
import {SceneControl} from "./src/scene.js";
|
||||||
|
import {downloadUtility, compatibleCore} from "./src/misc.js";
|
||||||
|
import {TokenHelper} from "./src/systems/tokenHelper.js";
|
||||||
export var streamDeck;
|
export var streamDeck;
|
||||||
export var tokenControl;
|
export var tokenControl;
|
||||||
var move;
|
|
||||||
export var macroControl;
|
export var macroControl;
|
||||||
export var combatTracker;
|
export var combatTracker;
|
||||||
export var playlistControl;
|
export var playlistControl;
|
||||||
export var soundboard;
|
export var soundboard;
|
||||||
export var otherControls;
|
export var otherControls;
|
||||||
|
export var externalModules;
|
||||||
|
export var sceneControl;
|
||||||
|
export var tokenHelper;
|
||||||
|
|
||||||
export const moduleName = "MaterialDeck";
|
export const moduleName = "MaterialDeck";
|
||||||
export var selectedTokenId;
|
|
||||||
|
|
||||||
let ready = false;
|
let ready = false;
|
||||||
let activeSounds = [];
|
|
||||||
|
export let hotbarUses = false;
|
||||||
|
export let calculateHotbarUses;
|
||||||
|
|
||||||
|
let controlTokenTimer;
|
||||||
|
|
||||||
|
export let sdVersion;
|
||||||
|
export let msVersion;
|
||||||
|
|
||||||
//CONFIG.debug.hooks = true;
|
//CONFIG.debug.hooks = true;
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@@ -36,6 +47,8 @@ let wsOpen = false; //Bool for checking if websocket has ever been o
|
|||||||
let wsInterval; //Interval timer to detect disconnections
|
let wsInterval; //Interval timer to detect disconnections
|
||||||
let WSconnected = false;
|
let WSconnected = false;
|
||||||
|
|
||||||
|
//let furnace = game.modules.get("furnace");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Analyzes the message received
|
* Analyzes the message received
|
||||||
*
|
*
|
||||||
@@ -47,64 +60,113 @@ async function analyzeWSmessage(msg){
|
|||||||
//console.log("Received",data);
|
//console.log("Received",data);
|
||||||
|
|
||||||
if (data.type == "connected" && data.data == "SD"){
|
if (data.type == "connected" && data.data == "SD"){
|
||||||
|
const msg = {
|
||||||
|
target: "SD",
|
||||||
|
type: "init",
|
||||||
|
system: game.system.id
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify(msg));
|
||||||
|
|
||||||
|
|
||||||
console.log("streamdeck connected to server");
|
console.log("streamdeck connected to server");
|
||||||
|
streamDeck.resetImageBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.type == "version" && data.source == "SD") {
|
||||||
|
let minimumSDversion;
|
||||||
|
let minimumMSversion;
|
||||||
|
if (compatibleCore("0.8.5")) {
|
||||||
|
minimumSDversion = game.modules.get("MaterialDeck").data.flags.minimumSDversion.replace('v','');
|
||||||
|
minimumMSversion = game.modules.get("MaterialDeck").data.flags.minimumMSversion;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
minimumSDversion = game.modules.get("MaterialDeck").data.minimumSDversion.replace('v','');
|
||||||
|
minimumMSversion = game.modules.get("MaterialDeck").data.minimumMSversion;
|
||||||
|
}
|
||||||
|
|
||||||
|
sdVersion = data.version;
|
||||||
|
|
||||||
|
if (data.version < minimumSDversion) {
|
||||||
|
let d = new Dialog({
|
||||||
|
title: "Material Deck: Update Needed",
|
||||||
|
content: "<p>The Stream Deck plugin version you're using is v" + data.version + ", which is incompatible with this verion of the module.<br>Update to v" + minimumSDversion + " or newer.</p>",
|
||||||
|
buttons: {
|
||||||
|
download: {
|
||||||
|
icon: '<i class="fas fa-download"></i>',
|
||||||
|
label: "Download Utility",
|
||||||
|
callback: () => new downloadUtility()
|
||||||
|
},
|
||||||
|
ignore: {
|
||||||
|
icon: '<i class="fas fa-times"></i>',
|
||||||
|
label: "Ignore"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
default: "download"
|
||||||
|
});
|
||||||
|
d.render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (data == undefined || data.payload == undefined) return;
|
if (data == undefined || data.payload == undefined) return;
|
||||||
|
//console.log("Received",data);
|
||||||
const action = data.action;
|
const action = data.action;
|
||||||
const event = data.event;
|
const event = data.event;
|
||||||
const context = data.context;
|
const context = data.context;
|
||||||
const coordinates = data.payload.coordinates;
|
const coordinates = data.payload.coordinates;
|
||||||
if (coordinates == undefined) coordinates = 0;
|
|
||||||
const settings = data.payload.settings;
|
const settings = data.payload.settings;
|
||||||
|
const device = data.device;
|
||||||
|
|
||||||
|
|
||||||
if (data.data == 'init'){
|
if (data.data == 'init'){
|
||||||
|
|
||||||
}
|
}
|
||||||
if (event == 'willAppear' || event == 'didReceiveSettings'){
|
if (event == 'willAppear' || event == 'didReceiveSettings'){
|
||||||
|
if (coordinates == undefined) return;
|
||||||
streamDeck.setScreen(action);
|
streamDeck.setScreen(action);
|
||||||
streamDeck.setContext(action,context,coordinates,settings);
|
await streamDeck.setContext(device,data.size,data.deviceIteration,action,context,coordinates,settings);
|
||||||
|
|
||||||
if (action == 'token'){
|
if (action == 'token'){
|
||||||
tokenControl.active = true;
|
tokenControl.active = true;
|
||||||
tokenControl.update(selectedTokenId);
|
tokenControl.pushData(canvas.tokens.controlled[0]?.id,settings,context,device);
|
||||||
}
|
}
|
||||||
else if (action == 'macro')
|
else if (action == 'macro')
|
||||||
macroControl.update(settings,context);
|
macroControl.update(settings,context,device);
|
||||||
else if (action == 'combattracker')
|
else if (action == 'combattracker')
|
||||||
combatTracker.update(settings,context);
|
combatTracker.update(settings,context,device);
|
||||||
else if (action == 'playlist')
|
else if (action == 'playlist')
|
||||||
playlistControl.update(settings,context);
|
playlistControl.update(settings,context,device);
|
||||||
else if (action == 'soundboard')
|
else if (action == 'soundboard')
|
||||||
soundboard.update(settings,context);
|
soundboard.update(settings,context,device);
|
||||||
else if (action == 'other')
|
else if (action == 'other')
|
||||||
otherControls.update(settings,context);
|
otherControls.update(settings,context,device);
|
||||||
|
else if (action == 'external')
|
||||||
|
externalModules.update(settings,context,device);
|
||||||
|
else if (action == 'scene')
|
||||||
|
sceneControl.update(settings,context,device);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (event == 'willDisappear'){
|
else if (event == 'willDisappear'){
|
||||||
streamDeck.clearContext(action,coordinates);
|
if (coordinates == undefined) return;
|
||||||
|
streamDeck.clearContext(device,action,coordinates,context);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (event == 'keyDown'){
|
else if (event == 'keyDown'){
|
||||||
if (action == 'token')
|
if (action == 'token')
|
||||||
tokenControl.keyPress(settings);
|
tokenControl.keyPress(settings);
|
||||||
else if (action == 'move')
|
|
||||||
move.keyPress(settings);
|
|
||||||
else if (action == 'macro')
|
else if (action == 'macro')
|
||||||
macroControl.keyPress(settings);
|
macroControl.keyPress(settings);
|
||||||
else if (action == 'combattracker')
|
else if (action == 'combattracker')
|
||||||
combatTracker.keyPress(settings,context);
|
combatTracker.keyPress(settings,context,device);
|
||||||
else if (action == 'playlist')
|
else if (action == 'playlist')
|
||||||
playlistControl.keyPress(settings,context);
|
playlistControl.keyPress(settings,context,device);
|
||||||
else if (action == 'soundboard')
|
else if (action == 'soundboard')
|
||||||
soundboard.keyPressDown(settings);
|
soundboard.keyPressDown(settings);
|
||||||
else if (action == 'other')
|
else if (action == 'other')
|
||||||
otherControls.keyPress(settings);
|
otherControls.keyPress(settings,context,device);
|
||||||
|
else if (action == 'external')
|
||||||
|
externalModules.keyPress(settings,context,device);
|
||||||
|
else if (action == 'scene')
|
||||||
|
sceneControl.keyPress(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (event == 'keyUp'){
|
else if (event == 'keyUp'){
|
||||||
@@ -122,7 +184,10 @@ async function analyzeWSmessage(msg){
|
|||||||
*/
|
*/
|
||||||
function startWebsocket() {
|
function startWebsocket() {
|
||||||
const address = game.settings.get(moduleName,'address');
|
const address = game.settings.get(moduleName,'address');
|
||||||
ws = new WebSocket('ws://'+address+'/');
|
|
||||||
|
const url = address.startsWith('wss://') ? address : ('ws://'+address+'/');
|
||||||
|
|
||||||
|
ws = new WebSocket(url);
|
||||||
|
|
||||||
ws.onmessage = function(msg){
|
ws.onmessage = function(msg){
|
||||||
//console.log(msg);
|
//console.log(msg);
|
||||||
@@ -132,6 +197,7 @@ function startWebsocket() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ws.onopen = function() {
|
ws.onopen = function() {
|
||||||
|
messageCount = 0;
|
||||||
WSconnected = true;
|
WSconnected = true;
|
||||||
ui.notifications.info("Material Deck "+game.i18n.localize("MaterialDeck.Notifications.Connected") +": "+address);
|
ui.notifications.info("Material Deck "+game.i18n.localize("MaterialDeck.Notifications.Connected") +": "+address);
|
||||||
wsOpen = true;
|
wsOpen = true;
|
||||||
@@ -142,7 +208,8 @@ function startWebsocket() {
|
|||||||
ws.send(JSON.stringify(msg));
|
ws.send(JSON.stringify(msg));
|
||||||
const msg2 = {
|
const msg2 = {
|
||||||
target: "SD",
|
target: "SD",
|
||||||
type: "init"
|
type: "init",
|
||||||
|
system: game.system.id
|
||||||
}
|
}
|
||||||
ws.send(JSON.stringify(msg2));
|
ws.send(JSON.stringify(msg2));
|
||||||
clearInterval(wsInterval);
|
clearInterval(wsInterval);
|
||||||
@@ -152,13 +219,23 @@ function startWebsocket() {
|
|||||||
clearInterval(wsInterval);
|
clearInterval(wsInterval);
|
||||||
wsInterval = setInterval(resetWS, 10000);
|
wsInterval = setInterval(resetWS, 10000);
|
||||||
}
|
}
|
||||||
|
let messageCount = 0;
|
||||||
/**
|
/**
|
||||||
* Try to reset the websocket if a connection is lost
|
* Try to reset the websocket if a connection is lost
|
||||||
*/
|
*/
|
||||||
function resetWS(){
|
function resetWS(){
|
||||||
if (wsOpen) ui.notifications.warn("Material Deck: "+game.i18n.localize("MaterialDeck.Notifications.Disconnected"));
|
const maxMessages = game.settings.get(moduleName, 'nrOfConnMessages');
|
||||||
else ui.notifications.warn("Material Deck: "+game.i18n.localize("MaterialDeck.Notifications.ConnectFail"));
|
if (maxMessages == 0 || maxMessages > messageCount) {
|
||||||
|
messageCount++;
|
||||||
|
const countString = maxMessages == 0 ? "" : " (" + messageCount + "/" + maxMessages + ")";
|
||||||
|
if (wsOpen) {
|
||||||
|
ui.notifications.warn("Material Deck: "+game.i18n.localize("MaterialDeck.Notifications.Disconnected"));
|
||||||
|
wsOpen = false;
|
||||||
|
messageCount = 0;
|
||||||
|
}
|
||||||
|
else ui.notifications.warn("Material Deck: "+game.i18n.localize("MaterialDeck.Notifications.ConnectFail") + countString);
|
||||||
|
}
|
||||||
|
|
||||||
WSconnected = false;
|
WSconnected = false;
|
||||||
startWebsocket();
|
startWebsocket();
|
||||||
}
|
}
|
||||||
@@ -168,6 +245,22 @@ export function sendWS(txt){
|
|||||||
ws.send(txt);
|
ws.send(txt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isEmpty(obj) {
|
||||||
|
for(var key in obj) {
|
||||||
|
if(obj.hasOwnProperty(key))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPermission(action,func) {
|
||||||
|
const role = game.user.role-1;
|
||||||
|
const settings = game.settings.get(moduleName,'userPermission');
|
||||||
|
if (action == 'ENABLE') return settings.enable[role];
|
||||||
|
else return settings.permissions?.[action]?.[func]?.[role];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
//
|
//
|
||||||
// Hooks
|
// Hooks
|
||||||
@@ -178,53 +271,87 @@ export function sendWS(txt){
|
|||||||
* Ready hook
|
* Ready hook
|
||||||
* Attempt to open the websocket
|
* Attempt to open the websocket
|
||||||
*/
|
*/
|
||||||
Hooks.once('ready', ()=>{
|
Hooks.once('ready', async()=>{
|
||||||
|
registerSettings();
|
||||||
enableModule = (game.settings.get(moduleName,'Enable')) ? true : false;
|
enableModule = (game.settings.get(moduleName,'Enable')) ? true : false;
|
||||||
|
|
||||||
|
|
||||||
game.socket.on(`module.MaterialDeck`, (payload) =>{
|
|
||||||
//console.log(payload);
|
|
||||||
if (payload.msgType != "playSound") return;
|
|
||||||
playTrack(payload.trackNr,payload.src,payload.play,payload.repeat,payload.volume);
|
|
||||||
});
|
|
||||||
|
|
||||||
for (let i=0; i<64; i++)
|
|
||||||
activeSounds[i] = false;
|
|
||||||
|
|
||||||
if (enableModule == false) return;
|
|
||||||
if (game.user.isGM == false) {
|
|
||||||
ready = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
startWebsocket();
|
|
||||||
soundboard = new SoundboardControl();
|
soundboard = new SoundboardControl();
|
||||||
streamDeck = new StreamDeck();
|
streamDeck = new StreamDeck();
|
||||||
tokenControl = new TokenControl();
|
tokenControl = new TokenControl();
|
||||||
move = new Move();
|
|
||||||
macroControl = new MacroControl();
|
macroControl = new MacroControl();
|
||||||
combatTracker = new CombatTracker();
|
combatTracker = new CombatTracker();
|
||||||
playlistControl = new PlaylistControl();
|
playlistControl = new PlaylistControl();
|
||||||
otherControls = new OtherControls();
|
otherControls = new OtherControls();
|
||||||
|
externalModules = new ExternalModules();
|
||||||
|
sceneControl = new SceneControl();
|
||||||
|
tokenHelper = new TokenHelper();
|
||||||
|
|
||||||
|
game.socket.on(`module.MaterialDeck`, async(payload) =>{
|
||||||
|
//console.log(payload);
|
||||||
|
if (payload.msgType == "playSound") soundboard.playSound(payload.trackNr,payload.src,payload.play,payload.repeat,payload.volume);
|
||||||
|
else if (game.user.isGM && payload.msgType == "playPlaylist") {
|
||||||
|
const playlist = playlistControl.getPlaylist(payload.playlistNr);
|
||||||
|
playlistControl.playPlaylist(playlist,payload.playlistNr);
|
||||||
|
}
|
||||||
|
else if (game.user.isGM && payload.msgType == "playTrack") {
|
||||||
|
const playlist = playlistControl.getPlaylist(payload.playlistNr);
|
||||||
|
const sounds = playlist.data.sounds;
|
||||||
|
for (let track of sounds)
|
||||||
|
if (track._id == payload.trackId)
|
||||||
|
playlistControl.playTrack(track,playlist,payload.playlistNr)
|
||||||
|
}
|
||||||
|
else if (game.user.isGM && payload.msgType == "stopAllPlaylists")
|
||||||
|
playlistControl.stopAll(payload.force);
|
||||||
|
else if (game.user.isGM && payload.msgType == "soundboardUpdate") {
|
||||||
|
await game.settings.set(moduleName,'soundboardSettings',payload.settings);
|
||||||
|
const payloadNew = {
|
||||||
|
"msgType": "soundboardRefresh"
|
||||||
|
};
|
||||||
|
game.socket.emit(`module.MaterialDeck`, payloadNew);
|
||||||
|
}
|
||||||
|
else if (game.user.isGM == false && payload.msgType == "soundboardRefresh" && enableModule)
|
||||||
|
soundboard.updateAll();
|
||||||
|
else if (game.user.isGM && payload.msgType == "macroboardUpdate") {
|
||||||
|
await game.settings.set(moduleName,'macroSettings',payload.settings);
|
||||||
|
const payloadNew = {
|
||||||
|
"msgType": "macroboardRefresh"
|
||||||
|
};
|
||||||
|
game.socket.emit(`module.MaterialDeck`, payloadNew);
|
||||||
|
}
|
||||||
|
else if (game.user.isGM == false && payload.msgType == "macroboardRefresh" && enableModule)
|
||||||
|
macroControl.updateAll();
|
||||||
|
else if (game.user.isGM && payload.msgType == "playlistUpdate") {
|
||||||
|
await game.settings.set(moduleName,'playlists',payload.settings);
|
||||||
|
const payloadNew = {
|
||||||
|
"msgType": "playlistRefresh"
|
||||||
|
};
|
||||||
|
game.socket.emit(`module.MaterialDeck`, payloadNew);
|
||||||
|
}
|
||||||
|
else if (game.user.isGM == false && payload.msgType == "playlistRefresh" && enableModule)
|
||||||
|
playlistControl.updateAll();
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
let soundBoardSettings = game.settings.get(moduleName,'soundboardSettings');
|
if (game.user.isGM) {
|
||||||
let macroSettings = game.settings.get(moduleName, 'macroSettings');
|
let soundBoardSettings = game.settings.get(moduleName,'soundboardSettings');
|
||||||
let array = [];
|
let macroSettings = game.settings.get(moduleName, 'macroSettings');
|
||||||
for (let i=0; i<64; i++) array[i] = "";
|
let array = [];
|
||||||
let arrayVolume = [];
|
for (let i=0; i<64; i++) array[i] = "";
|
||||||
for (let i=0; i<64; i++) arrayVolume[i] = "50";
|
let arrayVolume = [];
|
||||||
let arrayZero = [];
|
for (let i=0; i<64; i++) arrayVolume[i] = "50";
|
||||||
for (let i=0; i<64; i++) arrayZero[i] = "0";
|
let arrayZero = [];
|
||||||
|
for (let i=0; i<64; i++) arrayZero[i] = "0";
|
||||||
if (macroSettings.color == undefined){
|
|
||||||
game.settings.set(moduleName,'macroSettings',{
|
if (macroSettings.color == undefined){
|
||||||
macros: array,
|
game.settings.set(moduleName,'macroSettings',{
|
||||||
color: arrayZero
|
macros: array,
|
||||||
});
|
color: arrayZero
|
||||||
}
|
});
|
||||||
if (soundBoardSettings.colorOff == undefined){
|
}
|
||||||
game.settings.set(moduleName,'soundboardSettings',{
|
|
||||||
|
const settings = {
|
||||||
playlist: "",
|
playlist: "",
|
||||||
sounds: array,
|
sounds: array,
|
||||||
colorOn: arrayZero,
|
colorOn: arrayZero,
|
||||||
@@ -232,37 +359,35 @@ Hooks.once('ready', ()=>{
|
|||||||
mode: arrayZero,
|
mode: arrayZero,
|
||||||
toggle: arrayZero,
|
toggle: arrayZero,
|
||||||
volume: arrayVolume
|
volume: arrayVolume
|
||||||
});
|
};
|
||||||
|
if (soundBoardSettings.colorOff == undefined){
|
||||||
|
game.settings.set(moduleName,'soundboardSettings',settings);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (enableModule == false) return;
|
||||||
|
if (getPermission('ENABLE') == false) {
|
||||||
|
ready = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startWebsocket();
|
||||||
|
|
||||||
|
const hotbarUsesTemp = game.modules.get("illandril-hotbar-uses");
|
||||||
|
if (hotbarUsesTemp != undefined) hotbarUses = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
export function playTrack(soundNr,src,play,repeat,volume){
|
|
||||||
if (play){
|
|
||||||
volume *= game.settings.get("core", "globalInterfaceVolume");
|
|
||||||
|
|
||||||
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
|
|
||||||
if (repeat == false){
|
|
||||||
activeSounds[soundNr] = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onstop: (id)=>{
|
|
||||||
activeSounds[soundNr] = false;
|
|
||||||
}});
|
|
||||||
howl.play();
|
|
||||||
activeSounds[soundNr] = howl;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
activeSounds[soundNr].stop();
|
|
||||||
activeSounds[soundNr] = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Hooks.on('updateToken',(scene,token)=>{
|
Hooks.on('updateToken',(scene,token)=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
let tokenId = token._id;
|
let tokenId = token._id;
|
||||||
if (tokenId == selectedTokenId)
|
if (tokenId == canvas.tokens.controlled[0]?.id) tokenControl.update(canvas.tokens.controlled[0]?.id);
|
||||||
tokenControl.update(selectedTokenId);
|
if (macroControl != undefined) macroControl.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('updateActor',(scene,actor)=>{
|
Hooks.on('updateActor',(scene,actor)=>{
|
||||||
@@ -271,37 +396,61 @@ Hooks.on('updateActor',(scene,actor)=>{
|
|||||||
for (let i=0; i<children.length; i++){
|
for (let i=0; i<children.length; i++){
|
||||||
if (children[i].actor.id == actor._id){
|
if (children[i].actor.id == actor._id){
|
||||||
let tokenId = children[i].id;
|
let tokenId = children[i].id;
|
||||||
if (tokenId == selectedTokenId)
|
if (tokenId == canvas.tokens.controlled[0]?.id) {
|
||||||
tokenControl.update(selectedTokenId);
|
tokenControl.update(canvas.tokens.controlled[0]?.id);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (macroControl != undefined) macroControl.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('controlToken',(token,controlled)=>{
|
Hooks.on('controlToken',(token,controlled)=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
if (controlled) {
|
if (controlled) {
|
||||||
selectedTokenId = token.data._id;
|
tokenControl.update(token.data._id);
|
||||||
|
if (controlTokenTimer != undefined) {
|
||||||
|
clearTimeout(controlTokenTimer);
|
||||||
|
controlTokenTimer = undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
selectedTokenId = undefined;
|
controlTokenTimer = setTimeout(function(){tokenControl.update(canvas.tokens.controlled[0]?.id);},10)
|
||||||
}
|
}
|
||||||
tokenControl.update(selectedTokenId);
|
|
||||||
|
if (macroControl != undefined) macroControl.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('updateOwnedItem',()=>{
|
||||||
|
if (macroControl != undefined) macroControl.updateAll();
|
||||||
|
})
|
||||||
|
|
||||||
Hooks.on('renderHotbar', (hotbar)=>{
|
Hooks.on('renderHotbar', (hotbar)=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
macroControl.hotbar(hotbar.macros);
|
if (macroControl != undefined) macroControl.hotbar(hotbar.macros);
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('render', (app)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
if (compatibleCore("0.8.1") == false) return;
|
||||||
|
if (app.id == "hotbar" && macroControl != undefined) macroControl.hotbar(app.macros);
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('renderCombatTracker',()=>{
|
Hooks.on('renderCombatTracker',()=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
combatTracker.updateAll();
|
if (combatTracker != undefined) combatTracker.updateAll();
|
||||||
tokenControl.update(selectedTokenId);
|
if (tokenControl != undefined) tokenControl.update(canvas.tokens.controlled[0]?.id);
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderActorSheet',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
if (tokenControl != undefined) tokenControl.update();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('renderPlaylistDirectory', (playlistDirectory)=>{
|
Hooks.on('renderPlaylistDirectory', (playlistDirectory)=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
playlistControl.updateAll();
|
if (playlistControl != undefined) playlistControl.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('closeplaylistConfigForm', (form)=>{
|
Hooks.on('closeplaylistConfigForm', (form)=>{
|
||||||
@@ -315,24 +464,45 @@ Hooks.on('pauseGame',()=>{
|
|||||||
otherControls.updateAll();
|
otherControls.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('renderSidebarTab',()=>{
|
Hooks.on('renderSidebarTab',(app)=>{
|
||||||
|
const options = {
|
||||||
|
sidebarTab: app.tabName,
|
||||||
|
renderPopout: app.popOut
|
||||||
|
}
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
otherControls.updateAll();
|
if (otherControls != undefined) otherControls.updateAll(options);
|
||||||
|
if (sceneControl != undefined) sceneControl.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('closeSidebarTab',(app)=>{
|
||||||
|
const options = {
|
||||||
|
sidebarTab: app.tabName,
|
||||||
|
renderPopout: false
|
||||||
|
}
|
||||||
|
if (otherControls != undefined) otherControls.updateAll(options);
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('changeSidebarTab',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
if (otherControls != undefined) otherControls.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('updateScene',()=>{
|
Hooks.on('updateScene',()=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
|
sceneControl.updateAll();
|
||||||
|
externalModules.updateAll();
|
||||||
otherControls.updateAll();
|
otherControls.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('renderSceneControls',()=>{
|
Hooks.on('renderSceneControls',()=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false || otherControls == undefined) return;
|
||||||
otherControls.updateAll();
|
otherControls.updateAll();
|
||||||
|
externalModules.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('targetToken',(user,token,targeted)=>{
|
Hooks.on('targetToken',(user,token,targeted)=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
if (token.id == selectedTokenId) tokenControl.update(selectedTokenId);
|
if (token.id == canvas.tokens.controlled[0]?.id) tokenControl.update(canvas.tokens.controlled[0]?.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('sidebarCollapse',()=>{
|
Hooks.on('sidebarCollapse',()=>{
|
||||||
@@ -350,79 +520,62 @@ Hooks.on('closeCompendium',()=>{
|
|||||||
otherControls.updateAll();
|
otherControls.updateAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('renderJournalSheet',()=>{
|
Hooks.on('renderCompendiumBrowser',()=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
otherControls.updateAll();
|
otherControls.updateAll({renderCompendiumBrowser:true});
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.on('closeJournalSheet',()=>{
|
Hooks.on('closeCompendiumBrowser',()=>{
|
||||||
if (enableModule == false || ready == false) return;
|
if (enableModule == false || ready == false) return;
|
||||||
otherControls.updateAll();
|
otherControls.updateAll({renderCompendiumBrowser:false});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderJournalSheet',(sheet)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
otherControls.updateAll({
|
||||||
|
hook:'renderJournalSheet',
|
||||||
|
sheet:sheet
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('closeJournalSheet',(sheet)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
otherControls.updateAll({
|
||||||
|
hook:'closeJournalSheet',
|
||||||
|
sheet:sheet
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('gmScreenOpenClose',(html,isOpen)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
externalModules.updateAll({gmScreen:isOpen});
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('ShareVision', ()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
externalModules.updateAll();
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on('NotYourTurn', ()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
externalModules.updateAll();
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on('pseudoclockSet', ()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
externalModules.updateAll();
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on('about-time.clockRunningStatus', ()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
externalModules.updateAll();
|
||||||
|
})
|
||||||
|
|
||||||
Hooks.once('init', ()=>{
|
Hooks.once('init', ()=>{
|
||||||
//CONFIG.debug.hooks = true;
|
//CONFIG.debug.hooks = true;
|
||||||
registerSettings(); //in ./src/settings.js
|
//registerSettings(); //in ./src/settings.js
|
||||||
});
|
});
|
||||||
|
|
||||||
Hooks.once('canvasReady',()=>{
|
Hooks.once('canvasReady',()=>{
|
||||||
ready = true;
|
ready = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
export function getFromJSONArray(data,i){
|
|
||||||
if (i>9) return 'nul';
|
|
||||||
let val;
|
|
||||||
if (i == 0) val = data.a;
|
|
||||||
else if (i == 1) val = data.a;
|
|
||||||
else if (i == 2) val = data.c;
|
|
||||||
else if (i == 3) val = data.d;
|
|
||||||
else if (i == 4) val = data.e;
|
|
||||||
else if (i == 5) val = data.f;
|
|
||||||
else if (i == 6) val = data.g;
|
|
||||||
else if (i == 7) val = data.h;
|
|
||||||
else if (i == 8) val = data.i;
|
|
||||||
else if (i == 9) val = data.j;
|
|
||||||
else if (i == 10) val = data.k;
|
|
||||||
else if (i == 11) val = data.l;
|
|
||||||
else if (i == 12) val = data.m;
|
|
||||||
else if (i == 13) val = data.n;
|
|
||||||
else if (i == 14) val = data.o;
|
|
||||||
else if (i == 15) val = data.p;
|
|
||||||
else if (i == 16) val = data.q;
|
|
||||||
else if (i == 17) val = data.r;
|
|
||||||
else if (i == 18) val = data.s;
|
|
||||||
else if (i == 19) val = data.t;
|
|
||||||
else if (i == 20) val = data.u;
|
|
||||||
else if (i == 21) val = data.v;
|
|
||||||
else if (i == 22) val = data.w;
|
|
||||||
else if (i == 23) val = data.x;
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setToJSONArray(data,i,val){
|
|
||||||
if (i>9) return 'nul';
|
|
||||||
if (i == 0) data.a = val;
|
|
||||||
else if (i == 1) data.b = val;
|
|
||||||
else if (i == 2) data.c = val;
|
|
||||||
else if (i == 3) data.d = val;
|
|
||||||
else if (i == 4) data.e = val;
|
|
||||||
else if (i == 5) data.f = val;
|
|
||||||
else if (i == 6) data.g = val;
|
|
||||||
else if (i == 7) data.h = val;
|
|
||||||
else if (i == 8) data.i = val;
|
|
||||||
else if (i == 9) data.j = val;
|
|
||||||
else if (i == 10) data.k = val;
|
|
||||||
else if (i == 11) data.l = val;
|
|
||||||
else if (i == 12) data.m = val;
|
|
||||||
else if (i == 13) data.n = val;
|
|
||||||
else if (i == 14) data.o = val;
|
|
||||||
else if (i == 15) data.p = val;
|
|
||||||
else if (i == 16) data.q = val;
|
|
||||||
else if (i == 17) data.r = val;
|
|
||||||
else if (i == 18) data.s = val;
|
|
||||||
else if (i == 19) data.t = val;
|
|
||||||
else if (i == 20) data.u = val;
|
|
||||||
else if (i == 21) data.v = val;
|
|
||||||
else if (i == 22) data.w = val;
|
|
||||||
else if (i == 23) data.x = val;
|
|
||||||
}
|
|
||||||
19
README.md
@@ -1,8 +1,12 @@
|
|||||||
<b>Note:</b> At the moment only Windows support has been confirmed. Right now it doesn't appear to work on MacOS. Linux support is unknown, there is no official Linux support for the Stream Deck, but there exist a 3rd party <a href="https://timothycrosley.com/project-7-streamdeck_ui">Stream Deck UI</a> that might be compatible.<br>
|
<b>Note:</b> At the moment Windows and OSX support has been confirmed. Linux support is unknown, there is no official Linux support for the Stream Deck, but there exist a 3rd party <a href="https://timothycrosley.com/project-7-streamdeck_ui">Stream Deck UI</a> that might be compatible.<br>
|
||||||
<b>In any case: Proceed at your own risk, I will not take any responsibility if you spent money and the module doesn't work!</b>
|
<b>In any case: Proceed at your own risk, I will not take any responsibility if you spent money and the module doesn't work!</b>
|
||||||
|
|
||||||
|
<b>Please read the documentation carefully, especially if you want to modify the default profile!</b>
|
||||||
|
|
||||||
I created a <a href="https://discord.gg/3hd4G6TkmA">Discord server</a> to discuss this and other hardware-based Foundry modules. Feel free to join if you'd like to join the discussion and be updated on this module.
|
I created a <a href="https://discord.gg/3hd4G6TkmA">Discord server</a> to discuss this and other hardware-based Foundry modules. Feel free to join if you'd like to join the discussion and be updated on this module.
|
||||||
|
|
||||||
|
[](https://youtu.be/7h5Ew8cJYxg "FoundryVTT Material Deck Demonstration")
|
||||||
|
|
||||||
# Material Deck
|
# Material Deck
|
||||||
Material Deck is a Foundry VTT module that allows you to control certain Foundry functions using an Elgato Stream Deck. A Stream Deck is a device that has physical buttons with displays behind them. Material Deck uses this to, for example, control playlists, execute macros, display and control the combat tracker.<br><br>
|
Material Deck is a Foundry VTT module that allows you to control certain Foundry functions using an Elgato Stream Deck. A Stream Deck is a device that has physical buttons with displays behind them. Material Deck uses this to, for example, control playlists, execute macros, display and control the combat tracker.<br><br>
|
||||||
The module allows a high degree of customization, where each button on the Stream Deck can be assigned any desired function. Furthermore, it supports folder structures, allowing easy switching between various button configurations so you can easily switch between the combat tracker, soundboard, or any other (custom) configuration.<br><br>
|
The module allows a high degree of customization, where each button on the Stream Deck can be assigned any desired function. Furthermore, it supports folder structures, allowing easy switching between various button configurations so you can easily switch between the combat tracker, soundboard, or any other (custom) configuration.<br><br>
|
||||||
@@ -21,15 +25,12 @@ The functions are categorized into actions. Here is a list of the available acti
|
|||||||
</ul>
|
</ul>
|
||||||
<li>Token Action: Display token info</li>
|
<li>Token Action: Display token info</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Display selected token's name, icon or stats (HP/AC/Movement/Initiative)</li>
|
<li>Display selected token's name, icon or stats (HP/AC/Movement/etc)</li>
|
||||||
<li>Open selected token's character sheet or token config</li>
|
<li>Open selected token's character sheet or token config</li>
|
||||||
|
<li>Target token</li>
|
||||||
|
<li>Toggle token visibility, combat state, conditions</li>
|
||||||
</ul>
|
</ul>
|
||||||
<li>Move Action: Move selected token or the canvas</li>
|
<li>Move Action: Move selected token or the canvas</li>
|
||||||
<ul>
|
|
||||||
<li>Move token (in a specified direction)</li>
|
|
||||||
<li>Move canvas (in a specified direction)</li>
|
|
||||||
<li>Zoom canvas in/out</li>
|
|
||||||
</ul>
|
|
||||||
<li>Macro Actions: Execute macros</li>
|
<li>Macro Actions: Execute macros</li>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Execute macro from hotbar</li>
|
<li>Execute macro from hotbar</li>
|
||||||
@@ -65,7 +66,7 @@ Instructions and more info can be found in the <a href="https://github.com/CDeen
|
|||||||
Module manifest: https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json
|
Module manifest: https://raw.githubusercontent.com/CDeenen/MaterialDeck/Master/module.json
|
||||||
|
|
||||||
## Software Versions & Module Incompatibilities
|
## Software Versions & Module Incompatibilities
|
||||||
<b>Foundry VTT:</b> Tested on 0.7.7<br>
|
<b>Foundry VTT:</b> Tested on 0.7.9 - 0.8.5<br>
|
||||||
<b>Module Incompatibilities:</b> None known.<br>
|
<b>Module Incompatibilities:</b> None known.<br>
|
||||||
|
|
||||||
## Feedback
|
## Feedback
|
||||||
@@ -75,6 +76,8 @@ If you have any suggestions or bugs to report, feel free to create an issue, con
|
|||||||
<b>Author:</b> Cristian Deenen (Cris#6864 on Discord)<br>
|
<b>Author:</b> Cristian Deenen (Cris#6864 on Discord)<br>
|
||||||
<br>
|
<br>
|
||||||
Special thanks to Asmodeus#7588 who made this module possible by generously donating a Stream Deck XL
|
Special thanks to Asmodeus#7588 who made this module possible by generously donating a Stream Deck XL
|
||||||
|
<br>
|
||||||
|
Please consider supporting me on <a href="https://www.patreon.com/materialfoundry">Patreon</a>, and feel free to join the Material Foundry <a href="https://discord.gg/3hd4G6TkmA">Discord</a> server.
|
||||||
|
|
||||||
## Abandonment
|
## Abandonment
|
||||||
Abandoned modules are a (potential) problem for Foundry, because users and/or other modules might rely on abandoned modules, which might break in future Foundry updates.<br>
|
Abandoned modules are a (potential) problem for Foundry, because users and/or other modules might rely on abandoned modules, which might break in future Foundry updates.<br>
|
||||||
|
|||||||
356
changelog.md
@@ -1,18 +1,368 @@
|
|||||||
# Changelog Material Deck Module
|
# Changelog Material Deck Module
|
||||||
|
### v1.4.4 - 26-05-2021
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Some small fixes to make the module compatible with Foundry 0.8.5</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Token Action => Added 'Page-Wide Token' option. All buttons on the current page (where the page is the collection of buttons that are shown) that have this enabled will use the same token</li>
|
||||||
|
<li>Token Action => On Click: Added 'Set Page-Wide Token' option, so you can configure buttons to set the page-wide token by pressing a button</li>
|
||||||
|
<li>Token Action: Added a 'Mode' select box. Setting it to 'Token' is the same as pre v1.4.4. New are the inventory, features and spellbook options that can be used to auto-populate buttons with items, features and spells.</li>
|
||||||
|
<li>Added a 'Clear Page' and 'Clear All' button to the soundboard and macroboard configuration</li>
|
||||||
|
<li>Added import and export buttons to the soundboard and macroboard configuration (only imports/exports metadata, not the actual audio files or the macros)</li>
|
||||||
|
<li>The number of connection error messages you will get is now configurable in the module settings</li>
|
||||||
|
<li>Added a download utility to the module settings, so you can easily version-check with the SD plugin and Material Server, download them and download profiles</li>
|
||||||
|
<li>Added Japanese localization (thanks BrotherSharper and Asami). All of the new features have not yet been translated</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Other:
|
||||||
|
<ul>
|
||||||
|
<li><b>(Breaking)</b> The Move Action has been removed. Moving tokens is not in the Token Action (it's an on click setting) and moving the canvas is in the Other Actions.</li>
|
||||||
|
<li>Major change to the soundboard and macroboard configuration. It is now displayed as pages of 16 sounds or 32 macros each, you can browse through the pages using the arrow keys at the top.</li>
|
||||||
|
<li>There is no longer a limit to the amount of sounds/macros you can assign to the soundboard/macroboard, but please note that at some point you might experience performance issues if there's too many sounds/macros.</li>
|
||||||
|
<li>Removed the 'Stream Deck Model' module setting, since it's not that useful</li>
|
||||||
|
<li>Token Action has been revamped to make it clearer and easier to implement new game systems</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.4.4 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.4.3 - 05-05-2021
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Fixed issue where the module would break if multiple Stream Decks were configured in the Stream Deck application, but not all of them had MD actions assigned to them</li>
|
||||||
|
<li>In the User Permission Configuration, the Scene Directory hint wasn't displayed properly</li>
|
||||||
|
<li>Got rid of warnings that popped up on initialization when using MD as a player</li>
|
||||||
|
<li>Fixed issue where the soundboard and macro board could not be configured by players, if it hadn't first been configured by a GM</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Other
|
||||||
|
<ul>
|
||||||
|
<li>Added compatibility for Foundry 0.8.2. Some functions no longer work in 0.8.1 (they still do in 0.7.9)</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.4.2 (unchanged): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.4.2 - 23-04-2021
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Last update I fixed the combat tracker, but this broke something in the Token Action (if you had a token selected, it would sometimes assumed you didn't have it selected), both should now work</li>
|
||||||
|
<li>Token Action: Plugin wouldn't save text boxes (such as 'Prepend Title' or 'Custom') if they were empty</li>
|
||||||
|
<li>Token Action: Improved performance, especially when 'Token' is set to 'Selected Token', and you're selecting a new token while you had another token selected<li>
|
||||||
|
<li>Token Action => Stats => Skill Modifier: (dnd5e) Would only display the modifier, now it displays the total value (so with proficiency, if applicable)</li>
|
||||||
|
<li>Combat Tracker => Mode: Function => Function: Would not always properly load the 'Turn Display' options</li>
|
||||||
|
<li>Playlist Action: Background color would not show, and 'Off Color' wouldn't work for 'Offset'</li>
|
||||||
|
<li>Macro Action => Macro Board => Offset: Background color would not show</li>
|
||||||
|
<li>Scene Action => Offset: Background color would not show</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Token Action: Changed the way how you can select what icon will be displayed. Instead of a true/false, there is now a selection box where you can select between 'None', 'Token Icon', 'Actor Icon' and 'Default', where the last one will display the default icon, for example the selected stat to display, the condition, etc</li>
|
||||||
|
<li>Token Action => Stats & On Click => Custom: Textbox now automatically resizes to fit the content</li>
|
||||||
|
<li>Token Action => On Click => Dice Roll: Added 'Roll Mode' option, where you can set to roll as 'default' (displays dialog), 'normal', 'advantage' or 'disadvantage'. All options, except for 'default', will ignore the previously added 'Token Roll Options' in 'Other Actions'</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Other:
|
||||||
|
<ul>
|
||||||
|
<li>Big code cleanup of the SD plugin</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.4.2 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.4.1 - 21-04-2021
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Previous update broke the combat tracker, should now be fixed</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
### v1.4.0 - 21-04-2021
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Support for connecting multiple Stream Decks at the same time. Please note that performance decreases with each extra Stream Deck</li>
|
||||||
|
<li>Other Actions: Added 'Token Roll Options'. This can toggle token rolls between showing a dialog and skipping the dialog and rolling normally or with advantage or disadvantage</li>
|
||||||
|
<li>If the SD plugin version you're using is outdated, you now get a pop-up to notify you of this and direct you to the download page</li>
|
||||||
|
<li>Added a module setting to set how dark the default white images should be. Can be lowered for improved readability of the text</li>
|
||||||
|
<li>Token Action => Stats: Added option to prepend text to the title, so you can set the stat to, for example, strength, and put 'STR: ' in the prepend textbox to display, for example, 'STR: +2'</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Token Action => Skill Roll: Setting wasn't saved in SD app</li>
|
||||||
|
<li>Token Action => Roll Ability: Rolling ability checks was broken for some systems</li>
|
||||||
|
<li>Token Action => Stats => Display HP: Read overlay indicating HP in the heart icon was also drawn when 'Display Token Icon' was enabled</li>
|
||||||
|
<li>Token Action => Stats: Added default images for all dnd5e abilities, saves and skills</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.4.0 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
|
||||||
|
### v1.3.3 - 12-04-2021
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Other Actions => Open Sidebar Tab: Action now indicates which sidebar tab is open (only works on Foundry 0.8.x)</li>
|
||||||
|
<li>Other Actions => Open Sidebar Tab: Added option to create an pop-out (doesn't work for the chat)</li>
|
||||||
|
<li>Other Actions: Added option to open the pf2e compendium browser</li>
|
||||||
|
<li>Macro Action: Can now call macros by name</li>
|
||||||
|
<li>Token Action => On Click: Added option to call a macro. Currently the macro will be applied to the selected token</li>
|
||||||
|
<li>Token Action => Display Stats: Added saving throws and skill modifiers for most systems</li>
|
||||||
|
<li>Token Action => OnClick: Added 'Dice Roll' option, which allows you to roll ability checks, saving throws and other things (depending on game system)</li>
|
||||||
|
<li>Token Action => Stats => Display HP: Made the heart icon dynamic, so the amount that the heart is filled with red depends on the relative amount of hit points of the token. 25% hp means the lower 25% of the heart is red, 50% hp means the lower 50% of the heart is red, etc</li>
|
||||||
|
<li>Token Action => Stats => Added a '+' before all modifier stats that are bigger than 0</li>
|
||||||
|
<li>Token Action => Custom OnClick: Added support for calling macros. For instructions, please refer to the documentation: https://github.com/CDeenen/MaterialDeck/wiki/Token-Action#custom-on-click-function</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Other Actions => Pause Game: Pause is now transmitted to all connected clients</li>
|
||||||
|
<li>Token Action => Display Stats: Fixed movement speed for pf2e</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Other:
|
||||||
|
<ul>
|
||||||
|
<li>Should be compatible with Foundry 0.8.1. Only tested on DnD5e. Please note that any functions that rely on other modules do not work if the other modules are not compatible with 0.8.1</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.3.4 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.3.2 - 11-03-2021
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Added support for the Multi Action provided by the SD app</li>
|
||||||
|
<li>External Modules Action => Added support for About Time</li>
|
||||||
|
<li>Token Action => Stats: Added 'Ability Scores', 'Ability Score Modifiers', 'Ability Score Saves' (dnd5e only) and 'Proficiency Bonus'</li>
|
||||||
|
<li>Token Action => Stats: Added 'HP (box)' option that displays a box with color that changes depending on the HP</li>
|
||||||
|
<li>Move Action: You can now choose what token should be moved, similar to the Token Action</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Playlist Action => Relative Offset: Fixed issue with displaying the target playlist name</li>
|
||||||
|
<li>Macro Action: Fixed Hotbar Uses for Shadow of the Demonlord</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Other:
|
||||||
|
<ul>
|
||||||
|
<li>Macro Action: Improved the way Hotbar Uses are displayed, it is now displayed in a box similar to how the module looks in Foundry</li>
|
||||||
|
<li>Made the way images are generated more flexible to make future additions easier</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.3.2 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.3.1 - 27-02-2021
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Token Action: You can now choose what token should be targeted with the action using: 'Selected Token', 'Token Name', 'Actor Name', 'Token Id' or 'Actor Id'. Added relevant user permissions to the permission configuration</li>
|
||||||
|
<li>Token Action => On Click: Added options 'Select Token' and 'Center on Token and Select Token'</li>
|
||||||
|
<li>Playlist Action: Added relative offset mode, with the option to display the offset target name for playlists</li>
|
||||||
|
<li>Playlist Action => Stop All: Added option to display the name of the playlist at the current offset</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Default user permissions would not be loaded if no previously saved permissions were present, resulting in MD assuming nobody has any permissions</li>
|
||||||
|
<li>Other Actions => Control Buttons => Lighting Controls: Would create a button for ambient sound instead of lighting</li>
|
||||||
|
<li>Token Action => Display Token Icon: It used to show the icon, even if unchecked, if no stat with default icon was selected</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.3.1 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.3.0 - 25-02-2021
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Material Deck can now be used by players. A 'User Permission Configuration' screen has been added to the module settings where the GM can deside what Material Deck functions are available to users</li>
|
||||||
|
<li>Macro Action: Added support for Illandril's Hotbar Uses (only requires the module to be installed, does not have to be active)</li>
|
||||||
|
<li>Token Action => OnClick: Added support for CUB conditions</li>
|
||||||
|
<li>External Modules => Added support for the 'Trigger Happy' module</li>
|
||||||
|
<li>External Modules => Added support for the 'MookAI' module</li>
|
||||||
|
<li>External Modules => Added support for the 'Shared Vision' module</li>
|
||||||
|
<li>External Modules => Added support for the 'Lock View' module</li>
|
||||||
|
<li>External Modules => Added support for the 'Not Your Turn' module</li>
|
||||||
|
</ul>
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Token Action => OnClick: Fixed conditions for pf1e and dnd3.5e</li>
|
||||||
|
</ul>
|
||||||
|
Other Changes:
|
||||||
|
<ul>
|
||||||
|
<li>Token and Combat Tracker Actions now autodetect the game system</li>
|
||||||
|
<li>Game-system related settings in the SD app unified and improved</li>
|
||||||
|
<li>Image Cache setting is no longer considered experimental</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<b>Note 1: </b>Because the module can now be used by players, some settings have been moved from 'world' settings to 'client' settings. This means that previous settings have been deleted, and they have to be set up again in the module settings.<br>
|
||||||
|
<b>Note 2: </b>You can give users access to the playlists, macro board and soundboard. Currently, everyone has to share the same configuration, so be careful with giving players permission to configure one of them.<br>
|
||||||
|
<b>Note 3: </b>Because of the new game system autodetection, some settings for non dnd5e systems might be deleted. You'll have to reconfigure them.<br>
|
||||||
|
<br>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.3.0 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.2.3 - 03-02-2021
|
||||||
|
Fixes:
|
||||||
|
<ul>
|
||||||
|
<li>Fixed some issues for the Shadow of the Demon Lord system</li>
|
||||||
|
</ul>
|
||||||
|
Other Changes:
|
||||||
|
<ul>
|
||||||
|
<li>Improved performance of the 'Playlist Configuration', 'Macro Configuration' and 'Soundboard Configuration' screens</li>
|
||||||
|
<li>Minor code clean-up</li>
|
||||||
|
</ul>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.2.2 (unchanged): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.2.2 - 02-02-2021
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Added a help button in the module configuration</li>
|
||||||
|
<li>Token Action: Added support for easy token wildcard image changes</li>
|
||||||
|
<li>Token Action: Added a comprehensive custom onClick function that can modify token and actor data, with support for basic mathematical expressions</li>
|
||||||
|
</ul>
|
||||||
|
Other Changes:
|
||||||
|
<ul>
|
||||||
|
<li>Improved GM screen compatibility</li>
|
||||||
|
</ul>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.2.2: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.2.1 - 07-01-2021
|
||||||
|
<b>Note:</b> Due to a change in how scene control is handled (moved from 'Other Controls' to its own 'Scene Action'), any actions related to scenes no longer work. You will have to set them up again using the new Scene Action.<br>
|
||||||
|
<br>
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>EXPERIMENTAL: Added an image buffer to prevent resending of images that have already been sent, giving a slight performance boost. Buffer size can be set in the module settings</li>
|
||||||
|
<li>Token Action => Display Stats: Added option to select a data path for an attribute</li>
|
||||||
|
<li>External Modules => GM Screen: Open and close the GM screen. Link to module: https://foundryvtt.com/packages/gm-screen/</li>
|
||||||
|
<li>Other Actions => Roll dice: Roll dice in foundry and select between public roll, private roll, or displaying result on the SD</li>
|
||||||
|
<li>Scene Action: Added way to create scene selection screen similar to soundboard/macro board. New functions to do this: 'Scene Directory' and 'Scene Offset'</li>
|
||||||
|
<li>Scene Action: Added 'Active Scene' function</li>
|
||||||
|
<li>Move Action => Selected Token: Added rotate to and rotate by functions</li>
|
||||||
|
<li>Token Action => On Click: Added 'Set Vision' option to set the token's vision and light emission</li>
|
||||||
|
<li>Other Actions => Send Chat Message: Send a message to the Foundry chat</li>
|
||||||
|
</ul>
|
||||||
|
Other Changes:
|
||||||
|
<ul>
|
||||||
|
<li>Plugin: Scene Action created that replaces Other Actions => Scene Selection</li>
|
||||||
|
<li>Plugin: Scene Action: Changed 'Any Scene' to 'Scene by Name'</li>
|
||||||
|
<li>Plugin: Actions are now ordered alphabetically</li>
|
||||||
|
<li>Plugin: Replaced color strings with color pickers</li>
|
||||||
|
<li>Various minor bug fixes</li>
|
||||||
|
</ul>
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.2.1: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.2.0 - 28-12-2020
|
||||||
|
Fixes
|
||||||
|
<ul>
|
||||||
|
<li>Incorrect link to some black backgrounds fixed</li>
|
||||||
|
<li>Token Action: Movement speed wouldn't be displayed for DnD5e 1.2.0</li>
|
||||||
|
<li>Macro Action => Hotbar: 10th macro would not trigger and display correctly</li>
|
||||||
|
<li>Combat Tracker Action => Function: Default value would not properly initialize</li>
|
||||||
|
<li>Other Actions => Darkness Control => Display would not function correctly</li>
|
||||||
|
<li>Fixed some issues in the SD plugin where correct settings would not be displayed</li>
|
||||||
|
</ul>
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Added new 'External Modules Action', which will contain all module integrations that don't fit anywhere else</li>
|
||||||
|
<li>Added support for the Custom Hotbar module in 'Macro Action' => Mode: 'Custom Hotbar'. Link to module: https://foundryvtt.com/packages/custom-hotbar/</li>
|
||||||
|
<li>Added support for the FxMaster module in 'External Modules Action' => Mode: 'Fx Master'. Link to module: https://foundryvtt.com/packages/fxmaster/</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
### v1.1.1 - 12-12-2020
|
||||||
|
Fixes
|
||||||
|
<ul>
|
||||||
|
<li>Fixed issue where deleting a playlist would cause an error preventing the Soundboard Configuration to show up</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.1.0 (unchanged): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.1.0 - 09-12-2020
|
||||||
|
Fixes
|
||||||
|
<ul>
|
||||||
|
<li>Settings would not show for Combat Tracker action</li>
|
||||||
|
<li>Macro Action => Macro Board default settings fixed</li>
|
||||||
|
<li>API has been improved, making integration with other hardware/software easier, and making future changes/additions easier</li>
|
||||||
|
</ul>
|
||||||
|
Additions:
|
||||||
|
<ul>
|
||||||
|
<li>Added support for Pathfinder 1e and Shadow of the Demon Lord</li>
|
||||||
|
<li>All dialogs that are openable using the SD can now be closed by pressing the button while the dialog is open</li>
|
||||||
|
<li>Playlist Action & Soundboard Action => Stop All now indicates if there are tracks/playlists/sounds playing</li>
|
||||||
|
<li>Confirmed Foundry 0.7.8 compatibility</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.1.0: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### V1.0.1 - 26-11-2020
|
||||||
|
<ul>
|
||||||
|
<li>Fixed issue where macro from macroboard wouldn't execute if furnace arguments were not defined</li>
|
||||||
|
<li>Fixed issue where soundboard wouldn't save if no previous data existed for that sound</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.0.0 (unchanged): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v1.0.0 - 24-11-2020
|
||||||
|
Release
|
||||||
|
<ul>
|
||||||
|
<li>Fixed issue where the last column in 'Soundboard Configuration' would not work properly</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
|
Material Server v1.0.2: https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
|
SD plugin v1.0.0: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
|
### v0.9.2 - 24-11-2020
|
||||||
|
<ul>
|
||||||
|
<li>Removed unnecessary errors when module is not fully configured</li>
|
||||||
|
<li>Solved issue that soundboard config couldn't be saved on a world that hadn't run Material Deck previously</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
### v0.9.1 - 23-11-2020
|
### v0.9.1 - 23-11-2020
|
||||||
<ul>
|
<ul>
|
||||||
<li>Fixed 'Playlist' action issue where 'TrackNr' wouldn't show</li>
|
<li>Fixed 'Playlist' action issue where 'TrackNr' wouldn't show</li>
|
||||||
<li>Fixed 'Soundboard Configuration' issue where changing the playlist would reset everything you've changed since last save</li>
|
<li>Fixed 'Soundboard Configuration' issue where changing the playlist would reset everything you've changed since last save</li>
|
||||||
<li>'Soundboard Configuration', 'Macro Configuration' and 'Playlist Configuration' now save after each change, and update the SD instantly</li>
|
<li>'Soundboard Configuration', 'Macro Configuration' and 'Playlist Configuration' now save after each change, and update the SD instantly</li>
|
||||||
<li>Save button has been removed from configuration screens, since it is now redundant</li>
|
<li>Save button has been removed from configuration screens, since it is now redundant</li>
|
||||||
|
<li>Added support for DnD3.5e and Pathfinder 2e</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<b>Note1:</b> In 'Macro Configuration', previously saved Furnace arguments have to be filled in again.<br>
|
<b>Note1:</b> In 'Macro Configuration', previously saved Furnace arguments have to be filled in again.<br>
|
||||||
<b>Note2:</b> Any settings set in 'Playlist Configuration' have to be set again<br>
|
<b>Note2:</b> Any settings set in 'Playlist Configuration' have to be set again<br>
|
||||||
<br>
|
<br>
|
||||||
<b>Compatible server app and SD plugin:</b><br>
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
Material Server v1.0.1: https://github.com/CDeenen/MaterialServer/releases <br>
|
Material Server v1.0.1 (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
|
||||||
SD plugin v0.9.1 (unchanged): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
SD plugin v0.9.1: https://github.com/CDeenen/MaterialDeck_SD/releases<br>
|
||||||
|
|
||||||
### v0.9.0 - 19-11-2020
|
### v0.9.0 - 19-11-2020
|
||||||
<ul>
|
<ul>
|
||||||
@@ -83,4 +433,4 @@ SD plugin v0.7.0<br>
|
|||||||
</ul>
|
</ul>
|
||||||
<b>Compatible server app and SD plugin:</b><br>
|
<b>Compatible server app and SD plugin:</b><br>
|
||||||
Server v0.2.4<br>
|
Server v0.2.4<br>
|
||||||
SD plugin v0.7.1<br>
|
SD plugin v0.7.1<br>
|
||||||
|
|||||||
BIN
img/.thumb/MaterialFoundry512x512.png.jpg
Normal file
|
After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
BIN
img/MaterialFoundry512x512.png
Normal file
|
After Width: | Height: | Size: 359 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
BIN
img/combattracker/.thumb/combattracker.png.jpg
Normal file
|
After Width: | Height: | Size: 6.6 KiB |
BIN
img/combattracker/.thumb/combattracker@2x.png.jpg
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
img/combattracker/.thumb/nextround.png.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
img/combattracker/.thumb/nextturn.png.jpg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
img/combattracker/.thumb/previousround.png.jpg
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
img/combattracker/.thumb/previousturn.png.jpg
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
img/combattracker/.thumb/startcombat.png.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
img/combattracker/.thumb/stopcombat.png.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
5
img/combattracker/SOURCES.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
combattracker.png: Edited from https://fontawesome.com/icons/fist-raised?style=solid
|
||||||
|
nextturn.png, previousturn.png: Edited from https://fontawesome.com/icons/arrow-right?style=solid
|
||||||
|
nextround.png, previousround.png: Edited from https://fontawesome.com/icons/step-forward?style=solid
|
||||||
|
startcombat.png: Edited from https://fontawesome.com/icons/play?style=solid
|
||||||
|
stopcombat.png: Edited from https://fontawesome.com/icons/stop?style=solid
|
||||||
BIN
img/combattracker/combattracker.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
img/combattracker/combattracker@2x.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
img/combattracker/nextround.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
img/combattracker/nextturn.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
img/combattracker/previousround.png
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
img/combattracker/previousturn.png
Normal file
|
After Width: | Height: | Size: 8.4 KiB |
BIN
img/combattracker/startcombat.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
img/combattracker/stopcombat.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
img/external/.thumb/external.png.jpg
vendored
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/external/.thumb/external@2x.png.jpg
vendored
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/external/.thumb/fxmaster.png.jpg
vendored
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
2
img/external/SOURCES.txt
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
external.png: Edited from https://fontawesome.com/icons/external-link-alt?style=solid
|
||||||
|
fxmaster.png: Edited from https://fontawesome.com/icons/magic?style=solid
|
||||||
BIN
img/external/external.png
vendored
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
img/external/external@2x.png
vendored
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
img/external/fxmaster.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
img/macro/.thumb/macro.png.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
img/macro/.thumb/macro@2x.png.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
1
img/macro/SOURCES.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
macro.png: Foundry's icon folder, converted from .svg, original name: dice-target.svg
|
||||||
BIN
img/macro/macro.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
img/macro/macro@2x.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
img/move/.thumb/center.png.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
img/move/.thumb/center@2x.png.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
img/move/.thumb/down.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/move/.thumb/downleft.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/move/.thumb/downright.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/move/.thumb/left.png.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
img/move/.thumb/right.png.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
img/move/.thumb/rotateccw.png.jpg
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
img/move/.thumb/rotatecw.png.jpg
Normal file
|
After Width: | Height: | Size: 8.2 KiB |
BIN
img/move/.thumb/up.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/move/.thumb/upleft.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/move/.thumb/upright.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/move/.thumb/zoomin.png.jpg
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
img/move/.thumb/zoomout.png.jpg
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
3
img/move/SOURCES.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
center.png: made by me.
|
||||||
|
rotatecw.png & rotateccw.png Edited from https://fontawesome.com/icons/sync-alt?style=solid.
|
||||||
|
All other images taken from freepngimg.com, iverted color and rotated. Source: https://freepngimg.com/png/24691-right-arrow-hd
|
||||||
BIN
img/move/center.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
img/move/center@2x.png
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
img/move/down.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
img/move/downleft.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
img/move/downright.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
img/move/left.png
Normal file
|
After Width: | Height: | Size: 8.0 KiB |
BIN
img/move/right.png
Normal file
|
After Width: | Height: | Size: 6.4 KiB |
BIN
img/move/rotateccw.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
img/move/rotatecw.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
img/move/up.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
img/move/upleft.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
img/move/upright.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
img/move/zoomin.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
img/move/zoomout.png
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
img/other/.thumb/cogs.png.jpg
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
img/other/.thumb/d20.png.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
img/other/.thumb/other.png.jpg
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
img/other/.thumb/other@2x.png.jpg
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
3
img/other/SOURCES.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
other.png: Made using https://www.elgato.com/en/gaming/keycreator
|
||||||
|
cogs.png: Edited from https://fontawesome.com/icons/cogs?style=solid
|
||||||
|
d20.png: Edited from https://game-icons.net/1x1/delapouite/dice-twenty-faces-twenty.html
|
||||||
BIN
img/other/cogs.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
img/other/d20.png
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
img/other/darkness/.thumb/darkness.png.jpg
Normal file
|
After Width: | Height: | Size: 7.5 KiB |
BIN
img/other/darkness/.thumb/decreasedarkness.png.jpg
Normal file
|
After Width: | Height: | Size: 6.0 KiB |
BIN
img/other/darkness/.thumb/increasedarkness.png.jpg
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
2
img/other/darkness/SOURCES.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
decreasedarkness.png: Made using https://www.elgato.com/en/gaming/keycreator
|
||||||
|
increasedarkness.png: Made using https://www.elgato.com/en/gaming/keycreator
|
||||||
BIN
img/other/darkness/darkness.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
img/other/darkness/decreasedarkness.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
img/other/darkness/increasedarkness.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
img/other/other.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
img/other/other@2x.png
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
img/other/pause/.thumb/pause.png.jpg
Normal file
|
After Width: | Height: | Size: 5.8 KiB |
BIN
img/other/pause/.thumb/playpause.png.jpg
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
img/other/pause/.thumb/resume.png.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
3
img/other/pause/SOURCES.txt
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
resume.png: Edited from https://fontawesome.com/icons/play?style=solid
|
||||||
|
pause.png: Edited from https://fontawesome.com/icons/pause?style=solid
|
||||||
|
playpause.png: Combined resume.png and pause.png
|
||||||
BIN
img/other/pause/pause.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
img/other/pause/playpause.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
img/other/pause/resume.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
img/playlist/.thumb/play.png.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
img/playlist/.thumb/play@2x.png.jpg
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
img/playlist/.thumb/play_redBrightness.png.jpg
Normal file
|
After Width: | Height: | Size: 5.1 KiB |
BIN
img/playlist/.thumb/stop.png.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
2
img/playlist/SOURCES.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
play.png: Edited from https://fontawesome.com/icons/play?style=solid
|
||||||
|
stop.png: Edited from https://fontawesome.com/icons/stop?style=solid
|
||||||
BIN
img/playlist/play.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
img/playlist/play@2x.png
Normal file
|
After Width: | Height: | Size: 7.6 KiB |
BIN
img/playlist/play_redBrightness.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
img/playlist/stop.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
img/soundboard/.thumb/soundboard.png.jpg
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
BIN
img/soundboard/.thumb/soundboard@2x.png.jpg
Normal file
|
After Width: | Height: | Size: 6.8 KiB |
BIN
img/soundboard/.thumb/stop.png.jpg
Normal file
|
After Width: | Height: | Size: 5.0 KiB |