v0.8.2
This commit is contained in:
347
MaterialDeck.js
Normal file
347
MaterialDeck.js
Normal file
@@ -0,0 +1,347 @@
|
|||||||
|
import {registerSettings} from "./src/settings.js";
|
||||||
|
import {StreamDeck} from "./src/streamDeck.js";
|
||||||
|
import {TokenControl} from "./src/token.js";
|
||||||
|
import {Move} from "./src/move.js";
|
||||||
|
import {MacroControl} from "./src/macro.js";
|
||||||
|
import {CombatTracker} from "./src/combattracker.js";
|
||||||
|
import {PlaylistControl} from "./src/playlist.js";
|
||||||
|
import {SoundboardControl} from "./src/soundboard.js";
|
||||||
|
import {OtherControls} from "./src/othercontrols.js";
|
||||||
|
export var streamDeck;
|
||||||
|
export var tokenControl;
|
||||||
|
var move;
|
||||||
|
export var macroControl;
|
||||||
|
var combatTracker;
|
||||||
|
var playlistControl;
|
||||||
|
var soundboard;
|
||||||
|
var otherControls;
|
||||||
|
|
||||||
|
export const moduleName = "MaterialDeck";
|
||||||
|
export var selectedTokenId;
|
||||||
|
|
||||||
|
let ready = false;
|
||||||
|
//CONFIG.debug.hooks = true;
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Global variables
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
var enableModule;
|
||||||
|
|
||||||
|
//Websocket variables
|
||||||
|
let ip = "localhost"; //Ip address of the websocket server
|
||||||
|
let port = "3003"; //Port of the websocket server
|
||||||
|
var ws; //Websocket variable
|
||||||
|
let wsOpen = false; //Bool for checking if websocket has ever been opened => changes the warning message if there's no connection
|
||||||
|
let wsInterval; //Interval timer to detect disconnections
|
||||||
|
let WSconnected = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Analyzes the message received
|
||||||
|
*
|
||||||
|
* @param {*} msg Message received
|
||||||
|
*/
|
||||||
|
async function analyzeWSmessage(msg,passthrough = false){
|
||||||
|
if (enableModule == false) return;
|
||||||
|
const data = JSON.parse(msg);
|
||||||
|
if (data == undefined || data.payload == undefined) return;
|
||||||
|
console.log(data);
|
||||||
|
const action = data.action;
|
||||||
|
const event = data.event;
|
||||||
|
const context = data.context;
|
||||||
|
const coordinates = data.payload.coordinates;
|
||||||
|
if (coordinates == undefined) coordinates = 0;
|
||||||
|
const settings = data.payload.settings;
|
||||||
|
|
||||||
|
|
||||||
|
if (data.data == 'init'){
|
||||||
|
|
||||||
|
}
|
||||||
|
if (event == 'willAppear' || event == 'didReceiveSettings'){
|
||||||
|
streamDeck.setScreen(action);
|
||||||
|
streamDeck.setContext(action,context,coordinates,settings);
|
||||||
|
|
||||||
|
if (action == 'token'){
|
||||||
|
if (selectedTokenId != undefined)
|
||||||
|
tokenControl.update(selectedTokenId);
|
||||||
|
}
|
||||||
|
else if (action == 'macro')
|
||||||
|
macroControl.update(settings,context);
|
||||||
|
else if (action == 'combattracker')
|
||||||
|
combatTracker.update(settings,context);
|
||||||
|
else if (action == 'playlist')
|
||||||
|
playlistControl.update(settings,context);
|
||||||
|
else if (action == 'soundboard')
|
||||||
|
soundboard.update(settings,context);
|
||||||
|
else if (action == 'other')
|
||||||
|
otherControls.update(settings,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event == 'willDisappear'){
|
||||||
|
streamDeck.clearContext(action,coordinates);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event == 'keyDown'){
|
||||||
|
if (action == 'token')
|
||||||
|
tokenControl.keyPress(settings);
|
||||||
|
else if (action == 'move')
|
||||||
|
move.keyPress(settings);
|
||||||
|
else if (action == 'macro')
|
||||||
|
macroControl.keyPress(settings);
|
||||||
|
else if (action == 'combattracker')
|
||||||
|
combatTracker.keyPress(settings,context);
|
||||||
|
else if (action == 'playlist')
|
||||||
|
playlistControl.keyPress(settings,context);
|
||||||
|
else if (action == 'soundboard'){
|
||||||
|
soundboard.keyPressDown(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (event == 'keyUp'){
|
||||||
|
if (action == 'soundboard'){
|
||||||
|
soundboard.keyPressUp(settings);
|
||||||
|
}
|
||||||
|
else if (action == 'other')
|
||||||
|
otherControls.keyPress(settings);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start a new websocket
|
||||||
|
* Start a 10s interval, if no connection is made, run resetWS()
|
||||||
|
* If connection is made, set interval to 1.5s to check for disconnects
|
||||||
|
* If message is received, reset the interval, and send the message to analyzeWSmessage()
|
||||||
|
*/
|
||||||
|
function startWebsocket() {
|
||||||
|
//ip = localhost;
|
||||||
|
ws = new WebSocket('ws://'+ip+':'+port+'/1');
|
||||||
|
|
||||||
|
ws.onmessage = function(msg){
|
||||||
|
//console.log(msg);
|
||||||
|
|
||||||
|
analyzeWSmessage(msg.data);
|
||||||
|
clearInterval(wsInterval);
|
||||||
|
wsInterval = setInterval(resetWS, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
ws.onopen = function() {
|
||||||
|
WSconnected = true;
|
||||||
|
ui.notifications.info("Material Deck Connected: "+ip+':'+port);
|
||||||
|
wsOpen = true;
|
||||||
|
let msg = {
|
||||||
|
type: "Foundry"
|
||||||
|
}
|
||||||
|
ws.send(JSON.stringify(msg));
|
||||||
|
clearInterval(wsInterval);
|
||||||
|
wsInterval = setInterval(resetWS, 5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
clearInterval(wsInterval);
|
||||||
|
wsInterval = setInterval(resetWS, 10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to reset the websocket if a connection is lost
|
||||||
|
*/
|
||||||
|
function resetWS(){
|
||||||
|
if (wsOpen) ui.notifications.warn("Material Deck: "+game.i18n.localize("MaterialDeck.Notifications.Disconnected"));
|
||||||
|
else ui.notifications.warn("Material Deck: "+game.i18n.localize("MaterialDeck.Notifications.ConnectFail"));
|
||||||
|
WSconnected = false;
|
||||||
|
startWebsocket();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function sendWS(txt){
|
||||||
|
if (WSconnected)
|
||||||
|
ws.send(txt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Hooks
|
||||||
|
//
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ready hook
|
||||||
|
* Attempt to open the websocket
|
||||||
|
*/
|
||||||
|
Hooks.once('ready', ()=>{
|
||||||
|
enableModule = (game.settings.get(moduleName,'Enable')) ? true : false;
|
||||||
|
if (enableModule == false) return;
|
||||||
|
|
||||||
|
game.socket.on(`module.MaterialDeck`, (payload) =>{
|
||||||
|
//console.log(payload);
|
||||||
|
if (payload.msgType != "playSound") return;
|
||||||
|
playTrack(payload.trackNr,payload.play,payload.repeat,payload.volume);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (game.user.isGM == false) {
|
||||||
|
ready = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
startWebsocket();
|
||||||
|
|
||||||
|
streamDeck = new StreamDeck();
|
||||||
|
tokenControl = new TokenControl();
|
||||||
|
move = new Move();
|
||||||
|
macroControl = new MacroControl();
|
||||||
|
combatTracker = new CombatTracker();
|
||||||
|
playlistControl = new PlaylistControl();
|
||||||
|
soundboard = new SoundboardControl();
|
||||||
|
otherControls = new OtherControls();
|
||||||
|
|
||||||
|
|
||||||
|
let soundBoardSettings = game.settings.get(moduleName,'soundboardSettings');
|
||||||
|
let macroSettings = game.settings.get(moduleName, 'macroSettings');
|
||||||
|
let array = [];
|
||||||
|
for (let i=0; i<64; i++) array[i] = "";
|
||||||
|
let arrayVolume = [];
|
||||||
|
for (let i=0; i<64; i++) arrayVolume[i] = "50";
|
||||||
|
let arrayZero = [];
|
||||||
|
for (let i=0; i<64; i++) arrayZero[i] = "0";
|
||||||
|
|
||||||
|
if (macroSettings.color == undefined){
|
||||||
|
game.settings.set(moduleName,'macroSettings',{
|
||||||
|
macros: array,
|
||||||
|
color: arrayZero
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (soundBoardSettings.colorOff == undefined){
|
||||||
|
game.settings.set(moduleName,'soundboardSettings',{
|
||||||
|
playlist: "",
|
||||||
|
sounds: array,
|
||||||
|
colorOn: arrayZero,
|
||||||
|
colorOff: arrayZero,
|
||||||
|
mode: arrayZero,
|
||||||
|
toggle: arrayZero,
|
||||||
|
volume: arrayVolume
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export function playTrack(soundNr,play,repeat,volume){
|
||||||
|
if (play){
|
||||||
|
let trackId = game.settings.get(moduleName,'soundboardSettings').sounds[soundNr];
|
||||||
|
let playlistId = game.settings.get(moduleName,'soundboardSettings').playlist;
|
||||||
|
let sounds = game.playlists.entities.find(p => p._id == playlistId).data.sounds;
|
||||||
|
let sound = sounds.find(p => p._id == trackId);
|
||||||
|
if (sound == undefined){
|
||||||
|
activeSounds[soundNr] = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
volume *= game.settings.get("core", "globalInterfaceVolume");
|
||||||
|
let src = sound.path;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Hooks.on('updateToken',(scene,token)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
let tokenId = token._id;
|
||||||
|
if (tokenId == selectedTokenId)
|
||||||
|
tokenControl.update(selectedTokenId);
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('controlToken',(token,controlled)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
if (controlled) {
|
||||||
|
selectedTokenId = token.data._id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectedTokenId = undefined;
|
||||||
|
}
|
||||||
|
tokenControl.update(selectedTokenId);
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderHotbar', (hotbar)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
macroControl.hotbar(hotbar.macros);
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderCombatTracker',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
combatTracker.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderPlaylistDirectory', (playlistDirectory)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
playlistControl.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('closeplaylistConfigForm', (form)=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
if (form.template == "./modules/MaterialDeck/templates/playlistConfig.html")
|
||||||
|
playlistControl.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('pauseGame',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
otherControls.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderSidebarTab',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
otherControls.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('updateScene',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
otherControls.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.on('renderSceneControls',()=>{
|
||||||
|
if (enableModule == false || ready == false) return;
|
||||||
|
otherControls.updateAll();
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.once('init', ()=>{
|
||||||
|
//CONFIG.debug.hooks = true;
|
||||||
|
registerSettings(); //in ./src/settings.js
|
||||||
|
});
|
||||||
|
|
||||||
|
Hooks.once('canvasReady',()=>{
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
}
|
||||||
0
changelog.md
Normal file
0
changelog.md
Normal file
BIN
img/.thumb/Black.png.jpg
Normal file
BIN
img/.thumb/Black.png.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
img/.thumb/transparant.png.jpg
Normal file
BIN
img/.thumb/transparant.png.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
img/Black.png
Normal file
BIN
img/Black.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
img/transparant.png
Normal file
BIN
img/transparant.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
39
lang/en.json
Normal file
39
lang/en.json
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
{
|
||||||
|
"MaterialDeck.Notifications.Disconnected": "Disconnected from mdServer, attempting to reconnect",
|
||||||
|
"MaterialDeck.Notifications.ConnectFail": "Can't connect to mdServer, retrying",
|
||||||
|
|
||||||
|
"MaterialDeck.Sett.PlaylistConfig": "Playlist Configuration",
|
||||||
|
"MaterialDeck.Sett.SoundboardConfig": "Soundboard Configuration",
|
||||||
|
"MaterialDeck.Sett.MacroConfig": "Macro Configuration",
|
||||||
|
"MaterialDeck.Sett.Brightness": "Brightness",
|
||||||
|
"MaterialDeck.Sett.Brightness_Hint": "LED brightness level",
|
||||||
|
"MaterialDeck.Sett.Enable": "Enable module",
|
||||||
|
|
||||||
|
"MaterialDeck.Playlist.Clear": "Clear data",
|
||||||
|
"MaterialDeck.Playlist.Playmethod.Header": "Play Method",
|
||||||
|
"MaterialDeck.Playlist.Playmethod.Label": "Method",
|
||||||
|
"MaterialDeck.Playlist.Playmethod.Unrestricted": "Unrestricted",
|
||||||
|
"MaterialDeck.Playlist.Playmethod.OneTrackPlaylist": "One track per playlist",
|
||||||
|
"MaterialDeck.Playlist.Playmethod.OneTrackTotal": "One track in total",
|
||||||
|
"MaterialDeck.Playlist.Playlists": "Playlists",
|
||||||
|
"MaterialDeck.Playlist.Playlist": "Playlist",
|
||||||
|
"MaterialDeck.Playlist.None": "None",
|
||||||
|
"MaterialDeck.Playlist.Save": "Save",
|
||||||
|
"MaterialDeck.Soundboard.Volume": "Volume",
|
||||||
|
|
||||||
|
"MaterialDeck.Soundboard.Sound": "Sound",
|
||||||
|
"MaterialDeck.Soundboard.Icon": "Icon",
|
||||||
|
"MaterialDeck.Soundboard.Playback": "Playback",
|
||||||
|
"MaterialDeck.Soundboard.Once": "Once",
|
||||||
|
"MaterialDeck.Soundboard.Repeat": "Repeat",
|
||||||
|
"MaterialDeck.Soundboard.Hold": "Hold",
|
||||||
|
"MaterialDeck.Soundboard.On": "On",
|
||||||
|
"MaterialDeck.Soundboard.Off": "Off",
|
||||||
|
|
||||||
|
"MaterialDeck.Macro.Macro": "Macro",
|
||||||
|
"MaterialDeck.Macro.Background": "Background",
|
||||||
|
"MaterialDeck.Macro.FurnaceArgs": "Furnace arguments",
|
||||||
|
|
||||||
|
"MaterialDeck.Name": "Name"
|
||||||
|
}
|
||||||
|
|
||||||
23
module.json
Normal file
23
module.json
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{
|
||||||
|
"name": "MaterialDeck",
|
||||||
|
"title": "Material Deck",
|
||||||
|
"description": "",
|
||||||
|
"version": "0.8.2",
|
||||||
|
"author": "CDeenen",
|
||||||
|
"esmodules": [
|
||||||
|
"./MaterialDeck.js"
|
||||||
|
],
|
||||||
|
"socket": true,
|
||||||
|
"minimumCoreVersion": "0.7.5",
|
||||||
|
"compatibleCoreVersion": "0.7.6",
|
||||||
|
"languages": [
|
||||||
|
{
|
||||||
|
"lang": "en",
|
||||||
|
"name": "English",
|
||||||
|
"path": "lang/en.json"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"url": "https://github.com/CDeenen/MaterialDeck",
|
||||||
|
"manifest": "",
|
||||||
|
"download": ""
|
||||||
|
}
|
||||||
194
src/combattracker.js
Normal file
194
src/combattracker.js
Normal file
@@ -0,0 +1,194 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {streamDeck, tokenControl} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class CombatTracker{
|
||||||
|
constructor(){
|
||||||
|
this.combatantLength = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAll(){
|
||||||
|
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'combattracker') continue;
|
||||||
|
await this.update(data.settings,data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(settings,context){
|
||||||
|
let ctFunction = settings.combatTrackerFunction;
|
||||||
|
if (ctFunction == undefined) ctFunction == 0;
|
||||||
|
|
||||||
|
|
||||||
|
let combat = game.combat;
|
||||||
|
let src = "action/images/black.png";
|
||||||
|
let txt = "";
|
||||||
|
let background = "#000000";
|
||||||
|
let mode = settings.combatTrackerMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
|
||||||
|
if (mode == 0){
|
||||||
|
if (combat != null && combat != undefined && combat.turns.length != 0){
|
||||||
|
let initiativeOrder = combat.turns;
|
||||||
|
let nr = settings.combatantNr - 1;
|
||||||
|
if (nr == undefined || nr < 1) nr = 0;
|
||||||
|
let combatantState = 1;
|
||||||
|
if (nr == combat.turn) combatantState = 2;
|
||||||
|
let combatant = initiativeOrder[nr]
|
||||||
|
|
||||||
|
if (combatant != undefined){
|
||||||
|
let tokenId = combatant.tokenId;
|
||||||
|
tokenControl.pushData(tokenId,settings,context,combatantState,'#cccc00');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == 1){
|
||||||
|
if (combat != null && combat != undefined && combat.started){
|
||||||
|
let tokenId = combat.combatant.tokenId;
|
||||||
|
tokenControl.pushData(tokenId,settings,context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
else if (mode == 2){
|
||||||
|
|
||||||
|
if (ctFunction == 0) {
|
||||||
|
if (combat == null || combat == undefined || combat.combatants.length == 0) {
|
||||||
|
src = "action/images/combattracker/startcombat.png";
|
||||||
|
background = "#000000";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (combat.started == false) {
|
||||||
|
src = "action/images/combattracker/startcombat.png";
|
||||||
|
background = "#008000";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
src = "action/images/combattracker/stopcombat.png";
|
||||||
|
background = "#FF0000";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (ctFunction == 1) {
|
||||||
|
src = "action/images/combattracker/nextturn.png";
|
||||||
|
}
|
||||||
|
else if (ctFunction == 2) {
|
||||||
|
src = "action/images/combattracker/previousturn.png";
|
||||||
|
}
|
||||||
|
else if (ctFunction == 3) {
|
||||||
|
src = "action/images/combattracker/nextround.png";
|
||||||
|
}
|
||||||
|
else if (ctFunction == 4) {
|
||||||
|
src = "action/images/combattracker/previousround.png";
|
||||||
|
}
|
||||||
|
else if (ctFunction == 5){
|
||||||
|
src = "action/images/black.png";
|
||||||
|
let round = 0;
|
||||||
|
let turn = 0;
|
||||||
|
if (combat != null && combat != undefined && combat.started != false){
|
||||||
|
round = combat.round;
|
||||||
|
turn = combat.turn+1;
|
||||||
|
}
|
||||||
|
if (settings.displayRound) txt += "Round\n"+round;
|
||||||
|
if (txt != "") txt += "\n";
|
||||||
|
if (settings.displayTurn) txt += "Turn\n"+turn;
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPress(settings,context){
|
||||||
|
let mode = parseInt(settings.combatTrackerMode);
|
||||||
|
if (isNaN(mode)) mode = 0;
|
||||||
|
|
||||||
|
if (mode < 2) {
|
||||||
|
let onClick = settings.onClick;
|
||||||
|
if (onClick == undefined) onClick = 0;
|
||||||
|
let tokenId;
|
||||||
|
let combat = game.combat;
|
||||||
|
if (mode == 0) {
|
||||||
|
if (combat != null && combat != undefined && combat.turns.length != 0){
|
||||||
|
let initiativeOrder = combat.turns;
|
||||||
|
let nr = settings.combatantNr - 1;
|
||||||
|
if (nr == undefined || nr < 1) nr = 0;
|
||||||
|
let combatantState = 1;
|
||||||
|
if (nr == combat.turn) combatantState = 2;
|
||||||
|
let combatant = initiativeOrder[nr]
|
||||||
|
|
||||||
|
if (combatant == undefined) return;
|
||||||
|
tokenId = combatant.tokenId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == 1)
|
||||||
|
if (combat != null && combat != undefined && combat.started)
|
||||||
|
tokenId = combat.combatant.tokenId;
|
||||||
|
|
||||||
|
let token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
|
||||||
|
if (token == undefined) return;
|
||||||
|
if (onClick == 0) //Do nothing
|
||||||
|
return;
|
||||||
|
else if (onClick == 1){ //select token
|
||||||
|
token.control();
|
||||||
|
}
|
||||||
|
else if (onClick == 2){ //center on token
|
||||||
|
let location = token.getCenter(token.x,token.y);
|
||||||
|
canvas.animatePan(location);
|
||||||
|
}
|
||||||
|
else if (onClick == 3){ //center on token and select
|
||||||
|
let location = token.getCenter(token.x,token.y);
|
||||||
|
canvas.animatePan(location);
|
||||||
|
token.control();
|
||||||
|
}
|
||||||
|
else if (onClick == 4){ //Open character sheet
|
||||||
|
token.actor.sheet.render(true);
|
||||||
|
}
|
||||||
|
else { //Open token config
|
||||||
|
token.sheet._render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (mode == 2){
|
||||||
|
let combat = game.combat;
|
||||||
|
if (combat == null || combat == undefined) return;
|
||||||
|
|
||||||
|
let ctFunction = settings.combatTrackerFunction;
|
||||||
|
if (ctFunction == undefined) ctFunction == 0;
|
||||||
|
|
||||||
|
if (ctFunction == 0){
|
||||||
|
let src;
|
||||||
|
let background;
|
||||||
|
if (game.combat.started){
|
||||||
|
game.combat.endCombat();
|
||||||
|
src = "action/images/combattracker/startcombat.png";
|
||||||
|
background = "#000000";
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
game.combat.startCombat();
|
||||||
|
src = "action/images/combattracker/stopcombat.png";
|
||||||
|
background = "#FF0000";
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(context,src,background);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (game.combat.started == false) return;
|
||||||
|
|
||||||
|
if (ctFunction == 1) game.combat.nextTurn();
|
||||||
|
else if (ctFunction == 2) game.combat.previousTurn();
|
||||||
|
else if (ctFunction == 3) game.combat.nextRound();
|
||||||
|
else if (ctFunction == 4) game.combat.previousRound();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
215
src/macro.js
Normal file
215
src/macro.js
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {streamDeck} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class MacroControl{
|
||||||
|
constructor(){
|
||||||
|
this.offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAll(){
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'macro') continue;
|
||||||
|
await this.update(data.settings,data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(settings,context){
|
||||||
|
let mode = settings.macroMode;
|
||||||
|
let displayName = settings.displayName;
|
||||||
|
let macroNumber = settings.macroNumber;
|
||||||
|
let background = settings.background;
|
||||||
|
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
|
||||||
|
macroNumber = 0;
|
||||||
|
}
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
if (displayName == undefined) displayName = false;
|
||||||
|
if (background == undefined) background = '#000000';
|
||||||
|
|
||||||
|
macroNumber = parseInt(macroNumber);
|
||||||
|
|
||||||
|
//Macro Hotbar
|
||||||
|
if (mode < 2){
|
||||||
|
let macroId
|
||||||
|
if (mode == 0) macroId = game.user.data.hotbar[macroNumber];
|
||||||
|
else {
|
||||||
|
let macros = game.macros.apps[0].macros;
|
||||||
|
for (let j=0; j<10; j++){
|
||||||
|
if (macros[j].key == macroNumber){
|
||||||
|
if (macros[j].macro == null) macroId == undefined;
|
||||||
|
else macroId = macros[j].macro._id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let src = "";
|
||||||
|
let name = "";
|
||||||
|
|
||||||
|
if (macroId != undefined){
|
||||||
|
let macro = game.macros._source.find(p => p._id == macroId);
|
||||||
|
if (macro != undefined) {
|
||||||
|
name += macro.name;
|
||||||
|
src += macro.img;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
streamDeck.setIcon(1,context,src,background);
|
||||||
|
if (displayName == 0) name = "";
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let name = "";
|
||||||
|
let src = '';
|
||||||
|
if (settings.macroBoardMode == 0) {
|
||||||
|
macroNumber += this.offset - 1;
|
||||||
|
if (macroNumber < 0) macroNumber = 0;
|
||||||
|
var macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber];
|
||||||
|
background = game.settings.get(MODULE.moduleName,'macroSettings').color[macroNumber];
|
||||||
|
|
||||||
|
if (background == undefined) background = '#000000';
|
||||||
|
src = "";
|
||||||
|
if (macroId != undefined){
|
||||||
|
let macro = game.macros._source.find(p => p._id == macroId);
|
||||||
|
if (macro != undefined) {
|
||||||
|
name += macro.name;
|
||||||
|
src += macro.img;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
src = "";
|
||||||
|
let onBackground = settings.onBackground;
|
||||||
|
if (onBackground == undefined) onBackground = '#00FF00';
|
||||||
|
let offBackground = settings.offBackground;
|
||||||
|
if (offBackground == undefined) offBackground = '#000000';
|
||||||
|
let macroOffset = parseInt(settings.macroOffset);
|
||||||
|
if (macroOffset == undefined || isNaN(macroOffset)) macroOffset = 0;
|
||||||
|
|
||||||
|
if (macroOffset == parseInt(this.offset)) background = onBackground;
|
||||||
|
else background = offBackground;
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(1,context,src,background);
|
||||||
|
if (displayName == 0) name = "";
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hotbar(macros){
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'macro') continue;
|
||||||
|
let context = data.context;
|
||||||
|
let mode = data.settings.macroMode;
|
||||||
|
let displayName = data.settings.displayName;
|
||||||
|
let macroNumber = data.settings.macroNumber;
|
||||||
|
let background = data.settings.background;
|
||||||
|
let src = "";
|
||||||
|
let name = "";
|
||||||
|
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
|
||||||
|
macroNumber = 1;
|
||||||
|
}
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
if (mode == 2) continue;
|
||||||
|
if (displayName == undefined) displayName = false;
|
||||||
|
if (background == undefined) background = '#000000';
|
||||||
|
|
||||||
|
let macroId;
|
||||||
|
if (mode == 0){
|
||||||
|
macroId = game.user.data.hotbar[macroNumber];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (let j=0; j<10; j++){
|
||||||
|
if (macros[j].key == macroNumber){
|
||||||
|
if (macros[j].macro == null) macroId == undefined;
|
||||||
|
else macroId = macros[j].macro._id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let macro = undefined;
|
||||||
|
if (macroId != undefined) macro = game.macros._source.find(p => p._id == macroId);
|
||||||
|
if (macro != undefined && macro != null) {
|
||||||
|
name += macro.name;
|
||||||
|
src += macro.img;
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(1,context,src,background);
|
||||||
|
if (displayName == 0) name = "";
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPress(settings){
|
||||||
|
let mode = settings.macroMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
|
||||||
|
if (mode == 0 || mode == 1){
|
||||||
|
let macroNumber = settings.macroNumber;
|
||||||
|
if(macroNumber == undefined || isNaN(parseInt(macroNumber))){
|
||||||
|
macroNumber = 0;
|
||||||
|
}
|
||||||
|
this.executeHotbar(macroNumber,mode);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (settings.macroBoardMode == 0)
|
||||||
|
this.executeBoard(macroNumber);
|
||||||
|
else {
|
||||||
|
let macroOffset = settings.macroOffset;
|
||||||
|
if (macroOffset == undefined) macroOffset = 0;
|
||||||
|
this.offset = macroOffset;
|
||||||
|
this.updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
executeHotbar(macroNumber,mode){
|
||||||
|
let macroId
|
||||||
|
if (mode == 0) macroId = game.user.data.hotbar[macroNumber];
|
||||||
|
else {
|
||||||
|
let macros = game.macros.apps[0].macros;
|
||||||
|
for (let j=0; j<10; j++){
|
||||||
|
if (macros[j].key == macroNumber){
|
||||||
|
if (macros[j].macro == null) macroId == undefined;
|
||||||
|
else macroId = macros[j].macro._id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (macroId == undefined) return;
|
||||||
|
let macro = game.macros.get(macroId);
|
||||||
|
macro.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
executeBoard(macroNumber){
|
||||||
|
macroNumber = parseInt(macroNumber);
|
||||||
|
macroNumber += this.offset - 1;
|
||||||
|
if (macroNumber < 0) macroNumber = 0;
|
||||||
|
var macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber];
|
||||||
|
|
||||||
|
if (macroId != undefined){
|
||||||
|
let macro = game.macros.get(macroId);
|
||||||
|
if (macro != undefined && macro != null) {
|
||||||
|
const args = game.settings.get(MODULE.moduleName,'macroArgs')[macroNumber];
|
||||||
|
let furnaceEnabled = false;
|
||||||
|
let furnace = game.modules.get("furnace");
|
||||||
|
if (furnace != undefined && furnace.active) furnaceEnabled = true;
|
||||||
|
if (args == "") furnaceEnabled = false;
|
||||||
|
if (furnaceEnabled == false) macro.execute();
|
||||||
|
else {
|
||||||
|
let chatData = {
|
||||||
|
user: game.user._id,
|
||||||
|
speaker: ChatMessage.getSpeaker(),
|
||||||
|
content: "/'" + macro.name + "' " + args
|
||||||
|
};
|
||||||
|
ChatMessage.create(chatData, {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
409
src/misc.js
Normal file
409
src/misc.js
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {macroControl} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class playlistConfigForm extends FormApplication {
|
||||||
|
constructor(data, options) {
|
||||||
|
super(data, options);
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Options for this FormApplication
|
||||||
|
*/
|
||||||
|
static get defaultOptions() {
|
||||||
|
return mergeObject(super.defaultOptions, {
|
||||||
|
id: "playlist-config",
|
||||||
|
title: "Material Deck: Playlist Config",
|
||||||
|
template: "./modules/MaterialDeck/templates/playlistConfig.html",
|
||||||
|
classes: ["sheet"],
|
||||||
|
width: 500
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide data to the template
|
||||||
|
*/
|
||||||
|
getData() {
|
||||||
|
const selectedPlaylists = game.settings.get(MODULE.moduleName,'selectedPlaylists');
|
||||||
|
let playlistData = {};
|
||||||
|
|
||||||
|
for (let i=0; i<9; i++){
|
||||||
|
let playlist;
|
||||||
|
playlist = MODULE.getFromJSONArray(selectedPlaylists,i);
|
||||||
|
|
||||||
|
let dataThis = {
|
||||||
|
iteration: i+1,
|
||||||
|
playlist: selectedPlaylists[i],
|
||||||
|
playlists: game.playlists.entities
|
||||||
|
}
|
||||||
|
MODULE.setToJSONArray(playlistData,i,dataThis);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.data && selectedPlaylists) {
|
||||||
|
this.data = selectedPlaylists;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
playlists: game.playlists.entities,
|
||||||
|
playlistData: playlistData,
|
||||||
|
playMethod: game.settings.get(MODULE.moduleName,'playlistMethod')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update on form submit
|
||||||
|
* @param {*} event
|
||||||
|
* @param {*} formData
|
||||||
|
*/
|
||||||
|
async _updateObject(event, formData) {
|
||||||
|
await game.settings.set(MODULE.moduleName,'selectedPlaylists', formData["selectedPlaylist"]);
|
||||||
|
await game.settings.set(MODULE.moduleName,'playlistMethod',formData["playMethod"]);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
export class macroConfigForm extends FormApplication {
|
||||||
|
constructor(data, options) {
|
||||||
|
super(data, options);
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Options for this FormApplication
|
||||||
|
*/
|
||||||
|
static get defaultOptions() {
|
||||||
|
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||||
|
let width;
|
||||||
|
if (streamDeckModel == 0)
|
||||||
|
width = 500;
|
||||||
|
else if (streamDeckModel == 1)
|
||||||
|
width= 800;
|
||||||
|
else
|
||||||
|
width = 1400;
|
||||||
|
|
||||||
|
return mergeObject(super.defaultOptions, {
|
||||||
|
id: "macro-config",
|
||||||
|
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.MacroConfig"),
|
||||||
|
template: "./modules/MaterialDeck/templates/macroConfig.html",
|
||||||
|
classes: ["sheet"],
|
||||||
|
width: width
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide data to the template
|
||||||
|
*/
|
||||||
|
getData() {
|
||||||
|
var selectedMacros = game.settings.get(MODULE.moduleName,'macroSettings').macros;
|
||||||
|
var color = game.settings.get(MODULE.moduleName,'macroSettings').color;
|
||||||
|
var args = game.settings.get(MODULE.moduleName,'macroArgs');
|
||||||
|
if (selectedMacros == undefined) selectedMacros = [];
|
||||||
|
if (color == undefined) color = [];
|
||||||
|
if (args == undefined) args = [];
|
||||||
|
let macroData = {};
|
||||||
|
let furnaceEnabled = false;
|
||||||
|
let furnace = game.modules.get("furnace");
|
||||||
|
if (furnace != undefined && furnace.active) furnaceEnabled = true;
|
||||||
|
let height = 95;
|
||||||
|
if (furnaceEnabled) height += 50;
|
||||||
|
|
||||||
|
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||||
|
let iMax,jMax;
|
||||||
|
if (streamDeckModel == 0){
|
||||||
|
jMax = 6;
|
||||||
|
iMax = 3;
|
||||||
|
}
|
||||||
|
else if (streamDeckModel == 1){
|
||||||
|
jMax = 6;
|
||||||
|
iMax = 5;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jMax = 8;
|
||||||
|
iMax = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let iteration = 0;
|
||||||
|
for (let j=0; j<jMax; j++){
|
||||||
|
let macroThis = {};
|
||||||
|
|
||||||
|
for (let i=0; i<iMax; i++){
|
||||||
|
let colorThis = color[iteration];
|
||||||
|
if (colorThis != undefined){
|
||||||
|
let colorCorrect = true;
|
||||||
|
if (colorThis[0] != '#') colorCorrect = false;
|
||||||
|
for (let k=0; k<6; k++){
|
||||||
|
if (parseInt(colorThis[k+1],16)>15)
|
||||||
|
colorCorrect = false;
|
||||||
|
}
|
||||||
|
if (colorCorrect == false) colorThis = '#000000';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
colorThis = '#000000';
|
||||||
|
|
||||||
|
let dataThis = {
|
||||||
|
iteration: iteration+1,
|
||||||
|
macro: selectedMacros[iteration],
|
||||||
|
color: colorThis,
|
||||||
|
macros:game.macros,
|
||||||
|
args: args[iteration],
|
||||||
|
furnace: furnaceEnabled
|
||||||
|
}
|
||||||
|
MODULE.setToJSONArray(macroThis,i,dataThis);
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
let data = {
|
||||||
|
dataThis: macroThis,
|
||||||
|
};
|
||||||
|
MODULE.setToJSONArray(macroData,j,data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
height: height,
|
||||||
|
macros: game.macros,
|
||||||
|
selectedMacros: selectedMacros,
|
||||||
|
macroData: macroData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update on form submit
|
||||||
|
* @param {*} event
|
||||||
|
* @param {*} formData
|
||||||
|
*/
|
||||||
|
async _updateObject(event, formData) {
|
||||||
|
await game.settings.set(MODULE.moduleName,'macroSettings',{
|
||||||
|
macros: formData["macros"],
|
||||||
|
color: formData["colorPicker"]
|
||||||
|
});
|
||||||
|
|
||||||
|
let furnace = game.modules.get("furnace");
|
||||||
|
if (furnace != undefined && furnace.active)
|
||||||
|
await game.settings.set(MODULE.moduleName,'macroArgs', formData["args"]);
|
||||||
|
macroControl.updateAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
export class soundboardConfigForm extends FormApplication {
|
||||||
|
constructor(data, options) {
|
||||||
|
super(data, options);
|
||||||
|
this.data = data;
|
||||||
|
//this.soundData = {};
|
||||||
|
this.playlist;
|
||||||
|
this.updatePlaylist = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default Options for this FormApplication
|
||||||
|
*/
|
||||||
|
static get defaultOptions() {
|
||||||
|
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||||
|
let width;
|
||||||
|
if (streamDeckModel == 0)
|
||||||
|
width = 500;
|
||||||
|
else if (streamDeckModel == 1)
|
||||||
|
width= 800;
|
||||||
|
else
|
||||||
|
width = 1400;
|
||||||
|
|
||||||
|
return mergeObject(super.defaultOptions, {
|
||||||
|
id: "soundboard-config",
|
||||||
|
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.SoundboardConfig"),
|
||||||
|
template: "./modules/MaterialDeck/templates/soundboardConfig.html",
|
||||||
|
classes: ["sheet"],
|
||||||
|
width: width,
|
||||||
|
height: 720
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getArray(data){
|
||||||
|
let array = [data.a,data.b,data.c,data.d,data.e,data.f,data.g,data.h];
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide data to the template
|
||||||
|
*/
|
||||||
|
getData() {
|
||||||
|
let playlistId = game.settings.get(MODULE.moduleName,'soundboardSettings').playlist;
|
||||||
|
if (this.updatePlaylist) playlistId = this.playlist;
|
||||||
|
this.updatePlaylist = false;
|
||||||
|
let playlist = 'none';
|
||||||
|
let sounds = [];
|
||||||
|
if (playlistId != undefined){
|
||||||
|
playlist = game.playlists.entities.find(p => p._id == playlistId);
|
||||||
|
if (playlist != undefined) sounds = playlist.sounds;
|
||||||
|
else playlist = 'none';
|
||||||
|
}
|
||||||
|
let selectedSounds = game.settings.get(MODULE.moduleName,'soundboardSettings').sounds;
|
||||||
|
let colorOn = game.settings.get(MODULE.moduleName,'soundboardSettings').colorOn;
|
||||||
|
let colorOff = game.settings.get(MODULE.moduleName,'soundboardSettings').colorOff;
|
||||||
|
let mode = game.settings.get(MODULE.moduleName,'soundboardSettings').mode;
|
||||||
|
let volume = game.settings.get(MODULE.moduleName,'soundboardSettings').volume;
|
||||||
|
let img = game.settings.get(MODULE.moduleName,'soundboardSettings').img;
|
||||||
|
let name = game.settings.get(MODULE.moduleName,'soundboardSettings').name;
|
||||||
|
|
||||||
|
if (selectedSounds == undefined) selectedSounds = [];
|
||||||
|
if (colorOn == undefined) colorOn = [];
|
||||||
|
if (colorOff == undefined) colorOff = [];
|
||||||
|
if (mode == undefined) mode = [];
|
||||||
|
if (img == undefined) img = [];
|
||||||
|
if (name == undefined) name = [];
|
||||||
|
let soundData = {};
|
||||||
|
|
||||||
|
let streamDeckModel = game.settings.get(MODULE.moduleName,'streamDeckModel');
|
||||||
|
let iMax,jMax;
|
||||||
|
if (streamDeckModel == 0){
|
||||||
|
jMax = 6;
|
||||||
|
iMax = 3;
|
||||||
|
}
|
||||||
|
else if (streamDeckModel == 1){
|
||||||
|
jMax = 6;
|
||||||
|
iMax = 5;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
jMax = 8;
|
||||||
|
iMax = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
let iteration = 0;
|
||||||
|
|
||||||
|
for (let j=0; j<jMax; j++){
|
||||||
|
let soundsThis = {};
|
||||||
|
for (let i=0; i<iMax; i++){
|
||||||
|
if (volume == undefined) volume = 50;
|
||||||
|
|
||||||
|
|
||||||
|
let dataThis = {
|
||||||
|
iteration: iteration+1,
|
||||||
|
sound: selectedSounds[iteration],
|
||||||
|
sounds: sounds,
|
||||||
|
colorOn: colorOn[iteration],
|
||||||
|
colorOff: colorOff[iteration],
|
||||||
|
mode: mode[iteration],
|
||||||
|
volume: volume[iteration],
|
||||||
|
imgPath: img[iteration],
|
||||||
|
name: name[iteration]
|
||||||
|
}
|
||||||
|
MODULE.setToJSONArray(soundsThis,i,dataThis);
|
||||||
|
iteration++;
|
||||||
|
}
|
||||||
|
let data = {
|
||||||
|
dataThis: soundsThis,
|
||||||
|
};
|
||||||
|
MODULE.setToJSONArray(soundData,j,data);
|
||||||
|
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
playlists: game.playlists.entities,
|
||||||
|
playlist: playlistId,
|
||||||
|
sounds: sounds,
|
||||||
|
selectedSound81: selectedSounds.a,
|
||||||
|
soundData: soundData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update on form submit
|
||||||
|
* @param {*} event
|
||||||
|
* @param {*} formData
|
||||||
|
*/
|
||||||
|
async _updateObject(event, formData) {
|
||||||
|
let length = formData["sounds"].length;
|
||||||
|
let img = [];
|
||||||
|
for (let i=0; i<length; i++){
|
||||||
|
let name = "img"+(i+1);
|
||||||
|
let src = formData[name];
|
||||||
|
img[i] = src;
|
||||||
|
}
|
||||||
|
|
||||||
|
await game.settings.set(MODULE.moduleName,'soundboardSettings',{
|
||||||
|
playlist: formData["playlist"],
|
||||||
|
sounds: formData["sounds"],
|
||||||
|
colorOn: formData["colorOn"],
|
||||||
|
colorOff: formData["colorOff"],
|
||||||
|
mode: formData["mode"],
|
||||||
|
img: img,
|
||||||
|
volume: formData["volume"],
|
||||||
|
name: formData["name"]
|
||||||
|
});
|
||||||
|
//MODULE.launchpad.audioSoundboardUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
async activateListeners(html) {
|
||||||
|
super.activateListeners(html);
|
||||||
|
const colorPickerOn = html.find("button[name='colorPickerOn']");
|
||||||
|
const colorPickerOff = html.find("button[name='colorPickerOff']");
|
||||||
|
const playlistSelect = html.find("select[name='playlist']");
|
||||||
|
const volumeSlider = html.find("input[name='volume']");
|
||||||
|
const soundSelect = html.find("select[name='sounds']");
|
||||||
|
|
||||||
|
/*
|
||||||
|
colorPickerOn.on('click',(event) => {
|
||||||
|
let target = event.currentTarget.value;
|
||||||
|
let color = document.getElementById("colorOn"+target).value;
|
||||||
|
if ((color < 0 && color > 127) || color == "") color = 0;
|
||||||
|
MODULE.launchpad.colorPicker(target,1,color);
|
||||||
|
|
||||||
|
});
|
||||||
|
colorPickerOff.on('click',(event) => {
|
||||||
|
let target = event.currentTarget.value;
|
||||||
|
let color = document.getElementById("colorOff"+target).value;
|
||||||
|
if ((color < 0 && color > 127) || color == "") color = 0;
|
||||||
|
MODULE.launchpad.colorPicker(target,0,color);
|
||||||
|
|
||||||
|
});
|
||||||
|
if (playlistSelect.length > 0) {
|
||||||
|
playlistSelect.on("change", event => {
|
||||||
|
this.playlist = event.target.value;
|
||||||
|
this.updatePlaylist = true;
|
||||||
|
this.render();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
volumeSlider.on('change', event => {
|
||||||
|
let id = event.target.id.replace('volume','');
|
||||||
|
let column = id%10-1;
|
||||||
|
let row = 8-Math.floor(id/10);
|
||||||
|
id = row*8+column;
|
||||||
|
let settings = game.settings.get(MODULE.moduleName,'soundboardSettings');
|
||||||
|
settings.volume[id] = event.target.value;
|
||||||
|
game.settings.set(MODULE.moduleName,'soundboardSettings',settings);
|
||||||
|
if (MODULE.launchpad.activeSounds[id] != false){
|
||||||
|
let volume = AudioHelper.inputToVolume(event.target.value/100) * game.settings.get("core", "globalInterfaceVolume");
|
||||||
|
MODULE.launchpad.activeSounds[id].volume(volume);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (soundSelect.length > 0) {
|
||||||
|
soundSelect.on("change",event => {
|
||||||
|
let id = event.target.id.replace('soundSelect','');
|
||||||
|
let column = id%10-1;
|
||||||
|
let row = 8-Math.floor(id/10);
|
||||||
|
id = row*8+column;
|
||||||
|
let settings = game.settings.get(MODULE.moduleName,'soundboardSettings');
|
||||||
|
settings.sounds[id] = event.target.value;
|
||||||
|
game.settings.set(MODULE.moduleName,'soundboardSettings',settings);
|
||||||
|
if (MODULE.launchpad.activeSounds[id] != false){
|
||||||
|
let mode = settings.mode[id];
|
||||||
|
let repeat = false;
|
||||||
|
if (mode == 1) repeat = true;
|
||||||
|
MODULE.launchpad.playSound(id,repeat,false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
85
src/move.js
Normal file
85
src/move.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class Move{
|
||||||
|
constructor(){
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPress(settings){
|
||||||
|
let dir = settings.dir;
|
||||||
|
let mode = settings.mode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
if (dir == undefined) dir = 0;
|
||||||
|
if (settings.mode == '1')
|
||||||
|
this.moveToken(MODULE.selectedTokenId,dir);
|
||||||
|
else
|
||||||
|
this.moveCanvas(dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
async moveToken(tokenId,dir){
|
||||||
|
if (tokenId == undefined) return;
|
||||||
|
|
||||||
|
const token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
|
||||||
|
const gridSize = canvas.scene.data.grid;
|
||||||
|
let x = token.x;
|
||||||
|
let y = token.y;
|
||||||
|
|
||||||
|
if (dir == '1') y -= gridSize;
|
||||||
|
else if (dir == '2') y += gridSize;
|
||||||
|
else if (dir == '3') x += gridSize;
|
||||||
|
else if (dir == '4') x -= gridSize;
|
||||||
|
else if (dir == '5') {
|
||||||
|
x += gridSize;
|
||||||
|
y -= gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '6') {
|
||||||
|
x -= gridSize;
|
||||||
|
y -= gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '7') {
|
||||||
|
x += gridSize;
|
||||||
|
y += gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '8') {
|
||||||
|
x -= gridSize;
|
||||||
|
y += gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '0') {
|
||||||
|
let location = token.getCenter(x,y);
|
||||||
|
canvas.animatePan(location);
|
||||||
|
}
|
||||||
|
if (game.user.isGM == false && (token.can(game.user,"control") == false || token.checkCollision(token.getCenter(x, y)))) return;
|
||||||
|
token.update({x:x,y:y});
|
||||||
|
};
|
||||||
|
|
||||||
|
moveCanvas(dir){
|
||||||
|
let viewPosition = canvas.scene._viewPosition;
|
||||||
|
const gridSize = canvas.scene.data.grid;
|
||||||
|
viewPosition.duration = 100;
|
||||||
|
|
||||||
|
if (dir == '1') viewPosition.y -= gridSize;
|
||||||
|
else if (dir == '2') viewPosition.y += gridSize;
|
||||||
|
else if (dir == '3') viewPosition.x += gridSize;
|
||||||
|
else if (dir == '4') viewPosition.x -= gridSize;
|
||||||
|
else if (dir == '5') {
|
||||||
|
viewPosition.x += gridSize;
|
||||||
|
viewPosition.y -= gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '6') {
|
||||||
|
viewPosition.x -= gridSize;
|
||||||
|
viewPosition.y -= gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '7') {
|
||||||
|
viewPosition.x += gridSize;
|
||||||
|
viewPosition.y += gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '8') {
|
||||||
|
viewPosition.x -= gridSize;
|
||||||
|
viewPosition.y += gridSize;
|
||||||
|
}
|
||||||
|
else if (dir == '0') {
|
||||||
|
viewPosition.x = (canvas.dimensions.sceneWidth+window.innerWidth)/2;
|
||||||
|
viewPosition.y = (canvas.dimensions.sceneHeight+window.innerHeight)/2;
|
||||||
|
}
|
||||||
|
canvas.animatePan(viewPosition);
|
||||||
|
}
|
||||||
|
}
|
||||||
501
src/othercontrols.js
Normal file
501
src/othercontrols.js
Normal file
@@ -0,0 +1,501 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {streamDeck} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class OtherControls{
|
||||||
|
constructor(){
|
||||||
|
this.offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAll(){
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'other') continue;
|
||||||
|
await this.update(data.settings,data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(settings,context){
|
||||||
|
let mode = settings.otherMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
|
||||||
|
if (mode == 0) { //pause
|
||||||
|
this.updatePause(settings.pauseFunction,context);
|
||||||
|
}
|
||||||
|
else if (mode == 1) { //scene selection
|
||||||
|
this.updateScene(settings,context);
|
||||||
|
}
|
||||||
|
else if (mode == 2){ //control buttons
|
||||||
|
this.updateControl(settings,context);
|
||||||
|
}
|
||||||
|
else if (mode == 3){ //darkness
|
||||||
|
this.updateDarkness(settings,context);
|
||||||
|
}
|
||||||
|
else if (mode == 4){ //roll tables
|
||||||
|
this.updateRollTable(settings,context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPress(settings){
|
||||||
|
let mode = settings.otherMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
|
||||||
|
if (mode == 0) { //pause
|
||||||
|
this.keyPressPause(settings.pauseFunction);
|
||||||
|
}
|
||||||
|
else if (mode == 1) { //scene
|
||||||
|
this.keyPressScene(settings);
|
||||||
|
}
|
||||||
|
else if (mode == 2) { //control buttons
|
||||||
|
this.keyPressControl(settings);
|
||||||
|
}
|
||||||
|
else if (mode == 3) { //darkness controll
|
||||||
|
this.keyPressDarkness(settings);
|
||||||
|
}
|
||||||
|
else if (mode == 4) { //roll tables
|
||||||
|
this.keyPressRollTable(settings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
updatePause(pauseFunction,context){
|
||||||
|
|
||||||
|
if (pauseFunction == undefined) pauseFunction = 0;
|
||||||
|
let src = "";
|
||||||
|
let name = "";
|
||||||
|
let background = "#000000";
|
||||||
|
if (pauseFunction == 0){ //Pause game
|
||||||
|
if (game.paused) background = "#00FF00"
|
||||||
|
src = 'action/images/other/pause/pause.png';
|
||||||
|
}
|
||||||
|
else if (pauseFunction == 1){ //Resume game
|
||||||
|
if (game.paused == false) background = "#00FF00"
|
||||||
|
src = 'action/images/other/pause/resume.png';
|
||||||
|
}
|
||||||
|
else if (pauseFunction == 2) { //toggle
|
||||||
|
if (game.paused == false) background = "#00FF00"
|
||||||
|
src = 'action/images/other/pause/playpause.png';
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressPause(pauseFunction){
|
||||||
|
if (pauseFunction == undefined) pauseFunction = 0;
|
||||||
|
if (pauseFunction == 0){ //Pause game
|
||||||
|
if (game.paused) return;
|
||||||
|
game.togglePause();
|
||||||
|
}
|
||||||
|
else if (pauseFunction == 1){ //Resume game
|
||||||
|
if (game.paused == false) return;
|
||||||
|
game.togglePause();
|
||||||
|
}
|
||||||
|
else if (pauseFunction == 2) { //toggle
|
||||||
|
game.togglePause();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
updateScene(settings,context){
|
||||||
|
let func = settings.sceneFunction;
|
||||||
|
if (func == undefined) func = 0;
|
||||||
|
|
||||||
|
if (func == 0){ //visible scenes
|
||||||
|
let nr = parseInt(settings.sceneNr);
|
||||||
|
if (isNaN(nr)) nr = 1;
|
||||||
|
nr--;
|
||||||
|
|
||||||
|
let background = settings.background;
|
||||||
|
if (background == undefined) background = "#000000";
|
||||||
|
|
||||||
|
let scene = game.scenes.apps[0].scenes[nr];
|
||||||
|
let name = "";
|
||||||
|
let src = "";
|
||||||
|
let ringColor = "#000000";
|
||||||
|
let ring = 1;
|
||||||
|
|
||||||
|
if (scene != undefined){
|
||||||
|
if (scene.isView) {
|
||||||
|
ringColor = "#00FF00";
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
if (settings.displaySceneName) name = scene.name;
|
||||||
|
if (settings.displaySceneIcon) src = scene.img;
|
||||||
|
if (scene.active) name += "\n(Active)";
|
||||||
|
}
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
streamDeck.setIcon(1, context,src,background,ring,ringColor);
|
||||||
|
}
|
||||||
|
else if (func == 1) { //all scenes
|
||||||
|
let name = settings.sceneName;
|
||||||
|
if (name == undefined) return;
|
||||||
|
|
||||||
|
let background = settings.background;
|
||||||
|
if (background == undefined) background = "#000000";
|
||||||
|
|
||||||
|
let src = "";
|
||||||
|
let ringColor = "#000000";
|
||||||
|
let ring = 1;
|
||||||
|
let scene = game.scenes.apps[1].entities.find(p=>p.data.name == name);
|
||||||
|
name = "";
|
||||||
|
if (scene != undefined){
|
||||||
|
if (scene.isView) {
|
||||||
|
ringColor = "#00FF00";
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
if (settings.displaySceneName) name = scene.name;
|
||||||
|
if (settings.displaySceneIcon) src = scene.img;
|
||||||
|
if (scene.active) name += "\n(Active)";
|
||||||
|
}
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
streamDeck.setIcon(1, context,src,background,ring,ringColor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressScene(settings){
|
||||||
|
let func = settings.sceneFunction;
|
||||||
|
if (func == undefined) func = 0;
|
||||||
|
if (func == 0){ //visible scenes
|
||||||
|
let viewFunc = settings.sceneViewFunction;
|
||||||
|
if (viewFunc == undefined) viewFunc = 0;
|
||||||
|
|
||||||
|
let nr = parseInt(settings.sceneNr);
|
||||||
|
if (isNaN(nr)) nr = 1;
|
||||||
|
nr--;
|
||||||
|
let scene = game.scenes.apps[0].scenes[nr];
|
||||||
|
|
||||||
|
if (scene != undefined){
|
||||||
|
if (viewFunc == 0){
|
||||||
|
scene.view();
|
||||||
|
}
|
||||||
|
else if (viewFunc == 1){
|
||||||
|
scene.activate();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (scene.isView) scene.activate();
|
||||||
|
scene.view();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
updateControl(settings,context){
|
||||||
|
let control = settings.control;
|
||||||
|
if (control == undefined) control = 0;
|
||||||
|
|
||||||
|
let tool = settings.tool;
|
||||||
|
if (tool == undefined) tool = 0;
|
||||||
|
|
||||||
|
const controlName = this.getControlName(control);
|
||||||
|
const toolName = this.getToolName(control,tool);
|
||||||
|
|
||||||
|
let txt = "";
|
||||||
|
let src = "";
|
||||||
|
let background = "#000000";
|
||||||
|
let ringColor = "#FF7B00"
|
||||||
|
let selectedControl;
|
||||||
|
let selectedTool;
|
||||||
|
let ring = 1;
|
||||||
|
let activeControl = ui.controls.activeControl;
|
||||||
|
let activeTool = ui.controls.activeTool;
|
||||||
|
|
||||||
|
if (control == 0){
|
||||||
|
let controlNr = parseInt(settings.controlNr);
|
||||||
|
if (isNaN(controlNr)) controlNr = 1;
|
||||||
|
controlNr--;
|
||||||
|
|
||||||
|
selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl);
|
||||||
|
if (selectedControl != undefined){
|
||||||
|
selectedTool = selectedControl.tools[controlNr];
|
||||||
|
if (selectedTool != undefined){
|
||||||
|
txt = game.i18n.localize(selectedTool.title);
|
||||||
|
src = selectedTool.icon;
|
||||||
|
if (selectedTool.toggle){
|
||||||
|
background = "#340057"
|
||||||
|
if (selectedTool.active)
|
||||||
|
ringColor = "#A600FF"
|
||||||
|
else
|
||||||
|
ringColor = "#340057"
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
else if (activeTool == selectedTool.name)
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectedControl = ui.controls.controls.find(c => c.name == controlName);
|
||||||
|
if (selectedControl != undefined){
|
||||||
|
if (tool == 0){ //open category
|
||||||
|
txt = game.i18n.localize(selectedControl.title);
|
||||||
|
src = selectedControl.icon;
|
||||||
|
if (activeControl == selectedControl.name)
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
selectedTool = selectedControl.tools.find(t => t.name == toolName);
|
||||||
|
if (selectedTool != undefined){
|
||||||
|
txt = game.i18n.localize(selectedTool.title);
|
||||||
|
src = selectedTool.icon;
|
||||||
|
if (selectedTool.toggle){
|
||||||
|
background = "#340057"
|
||||||
|
if (selectedTool.active)
|
||||||
|
ringColor = "#A600FF"
|
||||||
|
else
|
||||||
|
ringColor = "#340057"
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
else if (activeTool == selectedTool.name && activeControl == selectedControl.name)
|
||||||
|
ring = 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(1,context,src,background,ring,ringColor);
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressControl(settings){
|
||||||
|
let control = settings.control;
|
||||||
|
if (control == undefined) control = 0;
|
||||||
|
|
||||||
|
let tool = settings.tool;
|
||||||
|
if (tool == undefined) tool = 0;
|
||||||
|
|
||||||
|
const controlName = this.getControlName(control);
|
||||||
|
const toolName = this.getToolName(control,tool);
|
||||||
|
|
||||||
|
if (control == 0){ //displayed tools
|
||||||
|
let controlNr = parseInt(settings.controlNr);
|
||||||
|
if (isNaN(controlNr)) controlNr = 1;
|
||||||
|
controlNr--;
|
||||||
|
let selectedControl = ui.controls.controls.find(c => c.name == ui.controls.activeControl);
|
||||||
|
if (selectedControl != undefined){
|
||||||
|
let selectedTool = selectedControl.tools[controlNr];
|
||||||
|
if (selectedTool != undefined){
|
||||||
|
if (selectedTool.toggle){
|
||||||
|
let newValue = !selectedTool.active;
|
||||||
|
selectedTool.active = newValue;
|
||||||
|
}
|
||||||
|
else if (selectedTool.button){
|
||||||
|
selectedTool.onClick();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
selectedControl.activeTool = selectedTool.name;
|
||||||
|
ui.controls.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { //select control
|
||||||
|
let selectedControl = ui.controls.controls.find(c => c.name == controlName);
|
||||||
|
if (selectedControl != undefined){
|
||||||
|
if (tool == 0){ //open category
|
||||||
|
ui.controls.activeControl = controlName;
|
||||||
|
selectedControl.activeTool = selectedControl.activeTool;
|
||||||
|
canvas.getLayer(selectedControl.layer).activate();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let selectedTool = selectedControl.tools.find(t => t.name == toolName);
|
||||||
|
if (selectedTool != undefined){
|
||||||
|
ui.controls.activeControl = controlName;
|
||||||
|
canvas.getLayer(selectedControl.layer).activate();
|
||||||
|
if (selectedTool.toggle){
|
||||||
|
let newValue = !selectedTool.active;
|
||||||
|
selectedTool.active = newValue;
|
||||||
|
}
|
||||||
|
else if (selectedTool.button){
|
||||||
|
selectedTool.onClick();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
selectedControl.activeTool = toolName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui.controls.render();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//ui.controls.controls.find(c => c.name == 'token')
|
||||||
|
//ui.controls.controls.find(c => c.name == 'walls').tools.find(t => t.name == 'snap').active=false
|
||||||
|
//ui.controls.render()
|
||||||
|
|
||||||
|
getControlName(control){
|
||||||
|
control--;
|
||||||
|
let name;
|
||||||
|
if (control == 0) name = 'token';
|
||||||
|
else if (control == 1) name = 'measure';
|
||||||
|
else if (control == 2) name = 'tiles';
|
||||||
|
else if (control == 3) name = 'drawings';
|
||||||
|
else if (control == 4) name = 'walls';
|
||||||
|
else if (control == 5) name = 'lighting';
|
||||||
|
else if (control == 6) name = 'sounds';
|
||||||
|
else if (control == 7) name = 'notes';
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getToolName(control,tool){
|
||||||
|
control--;
|
||||||
|
tool--;
|
||||||
|
let name;
|
||||||
|
if (control == 0){ //basic controls
|
||||||
|
if (tool == 0) name = 'select';
|
||||||
|
else if (tool == 1) name = 'target';
|
||||||
|
else if (tool == 2) name = 'ruler';
|
||||||
|
}
|
||||||
|
else if (control == 1){ //measurement controls
|
||||||
|
if (tool == 0) name = 'circle';
|
||||||
|
else if (tool == 1) name = 'cone';
|
||||||
|
else if (tool == 2) name = 'rect';
|
||||||
|
else if (tool == 3) name = 'ray';
|
||||||
|
else if (tool == 4) name = 'clear';
|
||||||
|
}
|
||||||
|
else if (control == 2){ //tile controls
|
||||||
|
if (tool == 0) name = 'select';
|
||||||
|
else if (tool == 1) name = 'tile';
|
||||||
|
else if (tool == 2) name = 'browse';
|
||||||
|
}
|
||||||
|
else if (control == 3){ //drawing tools
|
||||||
|
if (tool == 0) name = 'select';
|
||||||
|
else if (tool == 1) name = 'rect';
|
||||||
|
else if (tool == 2) name = 'ellipse';
|
||||||
|
else if (tool == 3) name = 'polygon';
|
||||||
|
else if (tool == 4) name = 'freehand';
|
||||||
|
else if (tool == 5) name = 'text';
|
||||||
|
else if (tool == 6) name = 'configure';
|
||||||
|
else if (tool == 7) name = 'clear';
|
||||||
|
}
|
||||||
|
else if (control == 4){ //wall controls
|
||||||
|
if (tool == 0) name = 'select';
|
||||||
|
else if (tool == 1) name = 'walls';
|
||||||
|
else if (tool == 2) name = 'terrain';
|
||||||
|
else if (tool == 3) name = 'invisible';
|
||||||
|
else if (tool == 4) name = 'ethereal';
|
||||||
|
else if (tool == 5) name = 'doors';
|
||||||
|
else if (tool == 6) name = 'secret';
|
||||||
|
else if (tool == 7) name = 'clone';
|
||||||
|
else if (tool == 8) name = 'snap';
|
||||||
|
else if (tool == 9) name = 'clear';
|
||||||
|
}
|
||||||
|
else if (control == 5){ //lighting controls
|
||||||
|
if (tool == 0) name = 'light';
|
||||||
|
else if (tool == 1) name = 'day';
|
||||||
|
else if (tool == 2) name = 'night';
|
||||||
|
else if (tool == 3) name = 'reset';
|
||||||
|
else if (tool == 4) name = 'clear';
|
||||||
|
}
|
||||||
|
else if (control == 6){ //ambient sound controls
|
||||||
|
if (tool == 0) name = 'sound';
|
||||||
|
else if (tool == 1) name = 'clear';
|
||||||
|
}
|
||||||
|
else if (control == 7){ //journal notes
|
||||||
|
if (tool == 0) name = 'select';
|
||||||
|
else if (tool == 1) name = 'toggle';
|
||||||
|
else if (tool == 2) name = 'clear';
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
updateDarkness(settings,context){
|
||||||
|
let func = settings.darknessFunction;
|
||||||
|
if (func == undefined) func = 0;
|
||||||
|
|
||||||
|
let value = settings.darknessValue;
|
||||||
|
if (value == undefined) value = 0;
|
||||||
|
|
||||||
|
let background = settings.background;
|
||||||
|
if (background == undefined) background = "#000000";
|
||||||
|
|
||||||
|
let src = "";
|
||||||
|
let txt = "";
|
||||||
|
|
||||||
|
if (func == 0){ //value
|
||||||
|
src = 'action/images/other/darkness/darkness.png';
|
||||||
|
}
|
||||||
|
else if (func == 1){ //increase/decrease
|
||||||
|
if (value < 0) src = 'action/images/other/darkness/decreasedarkness.png';
|
||||||
|
else src = 'action/images/other/darkness/increasedarkness.png';
|
||||||
|
}
|
||||||
|
else if (func == 2){ //display darkness
|
||||||
|
src = 'action/images/other/darkness/darkness.png';
|
||||||
|
let darkness = Math.floor(canvas.scene.data.darkness*100)/100;
|
||||||
|
txt += darkness;
|
||||||
|
}
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
streamDeck.setIcon(0, context,src,background);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressDarkness(settings) {
|
||||||
|
let func = settings.darknessFunction;
|
||||||
|
if (func == undefined) func = 0;
|
||||||
|
|
||||||
|
let value = parseFloat(settings.darknessValue);
|
||||||
|
if (value == undefined) value = 0;
|
||||||
|
|
||||||
|
if (func == 0){ //value
|
||||||
|
canvas.scene.update({darkness: value});
|
||||||
|
}
|
||||||
|
else if (func == 1){ //increase/decrease
|
||||||
|
let darkness = canvas.scene.data.darkness;
|
||||||
|
darkness += -1*value;
|
||||||
|
if (darkness > 1) darkness = 1;
|
||||||
|
if (darkness < 0) darkness = 0;
|
||||||
|
canvas.scene.update({darkness: darkness});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
updateRollTable(settings,context){
|
||||||
|
let name = settings.rollTableName;
|
||||||
|
if (name == undefined) return;
|
||||||
|
|
||||||
|
let background = settings.background;
|
||||||
|
if (background == undefined) background = "#000000";
|
||||||
|
|
||||||
|
let table = game.tables.entities.find(p=>p.name == name);
|
||||||
|
|
||||||
|
let txt = "";
|
||||||
|
let src = "";
|
||||||
|
|
||||||
|
if (table != undefined) {
|
||||||
|
if (settings.displayRollIcon) src = table.data.img;
|
||||||
|
if (settings.displayRollName) txt = table.name;
|
||||||
|
}
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
streamDeck.setIcon(1, context,src,background);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressRollTable(settings){
|
||||||
|
let func = settings.rolltableFunction;
|
||||||
|
if (func == undefined) func = 0;
|
||||||
|
|
||||||
|
let name = settings.rollTableName;
|
||||||
|
if (name == undefined) return;
|
||||||
|
|
||||||
|
let background = settings.background;
|
||||||
|
if (background == undefined) background = "#000000";
|
||||||
|
|
||||||
|
let table = game.tables.entities.find(p=>p.name == name);
|
||||||
|
|
||||||
|
if (table != undefined) {
|
||||||
|
if (func == 0){ //open
|
||||||
|
table.sheet.render(true);
|
||||||
|
}
|
||||||
|
else if (func == 1) {//Public roll
|
||||||
|
table.draw({rollMode:"roll"});
|
||||||
|
}
|
||||||
|
else if (func == 2) {//private roll
|
||||||
|
table.draw({rollMode:"selfroll"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
224
src/playlist.js
Normal file
224
src/playlist.js
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {streamDeck} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class PlaylistControl{
|
||||||
|
constructor(){
|
||||||
|
this.playlistOffset = 0;
|
||||||
|
this.trackOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAll(){
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'playlist') continue;
|
||||||
|
await this.update(data.settings,data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(settings,context){
|
||||||
|
if (settings.playlistMode == undefined) settings.playlistMode = 0;
|
||||||
|
if (settings.playlistMode == 0){
|
||||||
|
this.updatePlaylist(settings,context);
|
||||||
|
}
|
||||||
|
else if (settings.playlistMode == 1){
|
||||||
|
this.updateTrack(settings,context);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let src = 'action/images/playlist/stop.png';
|
||||||
|
streamDeck.setIcon(0,context,src,settings.background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePlaylist(settings,context){
|
||||||
|
let name = "";
|
||||||
|
let src = 'action/images/Black.png';
|
||||||
|
let background = '#000000';
|
||||||
|
|
||||||
|
let playlistType = settings.playlistType;
|
||||||
|
if (playlistType == undefined) playlistType = 0;
|
||||||
|
|
||||||
|
//Play/Stop
|
||||||
|
if (playlistType == 0){
|
||||||
|
let playlistNr = parseInt(settings.playlistNr);
|
||||||
|
if (isNaN(playlistNr) || playlistNr < 1) playlistNr = 1;
|
||||||
|
playlistNr--;
|
||||||
|
playlistNr += this.playlistOffset;
|
||||||
|
|
||||||
|
let playBackground = settings.playBackground;
|
||||||
|
if (playBackground == undefined) playBackground == '#00FF00';
|
||||||
|
let stopBackground = settings.stopBackground;
|
||||||
|
if (stopBackground == undefined) stopBackground == '#FF0000';
|
||||||
|
|
||||||
|
let playlist = this.getPlaylist(playlistNr);
|
||||||
|
if (playlist != undefined){
|
||||||
|
if (playlist.playing) {
|
||||||
|
background = playBackground;
|
||||||
|
src = 'action/images/playlist/stop.png';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
background = stopBackground;
|
||||||
|
src = 'action/images/playlist/play.png';
|
||||||
|
}
|
||||||
|
if (settings.displayName)
|
||||||
|
name = playlist.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//Offset
|
||||||
|
else {
|
||||||
|
src = "";
|
||||||
|
let onBackground = settings.onBackground;
|
||||||
|
if (onBackground == undefined) onBackground = '#00FF00';
|
||||||
|
let offBackground = settings.offBackground;
|
||||||
|
if (offBackground == undefined) offBackground = '#000000';
|
||||||
|
|
||||||
|
let playlistOffset = parseInt(settings.offset);
|
||||||
|
if (isNaN(playlistOffset)) playlistOffset = 0;
|
||||||
|
if (playlistOffset == this.playlistOffset) background = onBackground;
|
||||||
|
else background = offBackground;
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
updateTrack(settings,context){
|
||||||
|
let name = "";
|
||||||
|
let src = 'action/images/Black.png';
|
||||||
|
let background = '#000000';
|
||||||
|
|
||||||
|
let playlistType = settings.playlistType;
|
||||||
|
if (playlistType == undefined) playlistType = 0;
|
||||||
|
|
||||||
|
//Play/Stop
|
||||||
|
if (playlistType == 0){
|
||||||
|
let playlistNr = parseInt(settings.playlistNr);
|
||||||
|
if (isNaN(playlistNr) || playlistNr < 1) playlistNr = 1;
|
||||||
|
playlistNr--;
|
||||||
|
playlistNr += this.playlistOffset;
|
||||||
|
let trackNr = parseInt(settings.trackNr);
|
||||||
|
if (isNaN(trackNr) || trackNr < 1) trackNr = 1;
|
||||||
|
trackNr--;
|
||||||
|
trackNr += this.trackOffset;
|
||||||
|
|
||||||
|
let playBackground = settings.playBackground;
|
||||||
|
if (playBackground == undefined) playBackground == '#00FF00';
|
||||||
|
let stopBackground = settings.stopBackground;
|
||||||
|
if (stopBackground == undefined) stopBackground == '#FF0000';
|
||||||
|
|
||||||
|
let playlist = this.getPlaylist(playlistNr);
|
||||||
|
if (playlist != undefined){
|
||||||
|
let track = playlist.data.sounds[trackNr];
|
||||||
|
if (track != undefined){
|
||||||
|
if (track.playing) {
|
||||||
|
background = playBackground;
|
||||||
|
src = 'action/images/playlist/stop.png';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
background = stopBackground;
|
||||||
|
src = 'action/images/playlist/play.png';
|
||||||
|
}
|
||||||
|
if (settings.displayName)
|
||||||
|
name = track.name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
//Offset
|
||||||
|
else {
|
||||||
|
src = "";
|
||||||
|
let onBackground = settings.onBackground;
|
||||||
|
if (onBackground == undefined) onBackground = '#00FF00';
|
||||||
|
let offBackground = settings.offBackground;
|
||||||
|
if (offBackground == undefined) offBackground = '#000000';
|
||||||
|
|
||||||
|
let trackOffset = parseInt(settings.offset);
|
||||||
|
if (isNaN(trackOffset)) trackOffset = 0;
|
||||||
|
if (trackOffset == this.trackOffset) background = onBackground;
|
||||||
|
else background = offBackground;
|
||||||
|
}
|
||||||
|
streamDeck.setIcon(0,context,src,background);
|
||||||
|
streamDeck.setTitle(name,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
stopAll(){
|
||||||
|
let playing = game.playlists.playing;
|
||||||
|
for (let i=0; i<playing.length; i++){
|
||||||
|
playing[i].stopAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPlaylist(num){
|
||||||
|
let playlistId = game.settings.get(MODULE.moduleName,'selectedPlaylists')[num];
|
||||||
|
return game.playlists.entities.find(p => p._id == playlistId);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPress(settings,context){
|
||||||
|
let playlistNr = settings.playlistNr;
|
||||||
|
if (playlistNr == undefined || playlistNr < 1) playlistNr = 1;
|
||||||
|
playlistNr--;
|
||||||
|
playlistNr += this.playlistOffset;
|
||||||
|
let trackNr = settings.trackNr;
|
||||||
|
if (trackNr == undefined || trackNr < 1) trackNr = 1;
|
||||||
|
trackNr--;
|
||||||
|
trackNr += this.trackOffset;
|
||||||
|
|
||||||
|
if (settings.playlistMode == undefined) settings.playlistMode = 0;
|
||||||
|
if (settings.playlistType == undefined) settings.playlistType = 0;
|
||||||
|
if (settings.playlistMode < 2){
|
||||||
|
if (settings.playlistType == 0) {
|
||||||
|
let playlist = this.getPlaylist(playlistNr);
|
||||||
|
if (playlist != undefined){
|
||||||
|
if (settings.playlistMode == 0)
|
||||||
|
this.playPlaylist(playlist);
|
||||||
|
else {
|
||||||
|
let track = playlist.data.sounds[trackNr];
|
||||||
|
if (track != undefined){
|
||||||
|
this.playTrack(track,playlist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (settings.playlistMode == 0) {
|
||||||
|
this.playlistOffset = parseInt(settings.offset);
|
||||||
|
if (isNaN(this.playlistOffset)) this.playlistOffset = 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.trackOffset = parseInt(settings.offset);
|
||||||
|
if (isNaN(this.trackOffset)) this.trackOffset = 0;
|
||||||
|
}
|
||||||
|
this.updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.stopAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async playPlaylist(playlist){
|
||||||
|
if (playlist.playing) {
|
||||||
|
playlist.stopAll();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let mode = game.settings.get(MODULE.moduleName,'playlistMethod');
|
||||||
|
if (mode == 2) await this.stopAll();
|
||||||
|
playlist.playAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
async playTrack(track,playlist){
|
||||||
|
let play;
|
||||||
|
if (track.playing)
|
||||||
|
play = false;
|
||||||
|
else {
|
||||||
|
play = true;
|
||||||
|
let mode = game.settings.get(MODULE.moduleName,'playlistMethod');
|
||||||
|
if (mode == 1) await playlist.stopAll();
|
||||||
|
else if (mode == 2) await this.stopAll();
|
||||||
|
}
|
||||||
|
await playlist.updateEmbeddedEntity("PlaylistSound", {_id: track._id, playing: play});
|
||||||
|
playlist.update({playing: play});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
97
src/settings.js
Normal file
97
src/settings.js
Normal file
@@ -0,0 +1,97 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import { playlistConfigForm, macroConfigForm, soundboardConfigForm } from "./misc.js";
|
||||||
|
|
||||||
|
export const registerSettings = function() {
|
||||||
|
/**
|
||||||
|
* Main settings
|
||||||
|
*/
|
||||||
|
|
||||||
|
//Enabled the module
|
||||||
|
game.settings.register(MODULE.moduleName,'Enable', {
|
||||||
|
name: "MaterialDeck.Sett.Enable",
|
||||||
|
scope: "world",
|
||||||
|
config: true,
|
||||||
|
default: true,
|
||||||
|
type: Boolean,
|
||||||
|
onChange: x => window.location.reload()
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.register(MODULE.moduleName,'streamDeckModel', {
|
||||||
|
name: "Stream Deck Model",
|
||||||
|
hint: "Reduces the amount of macros and sounds in the macro and soundboard configuration screens. Gives a better overview, but if desired it can be set to XL to get the maximum number. This doesn't influence the operation of the module.",
|
||||||
|
scope: "world",
|
||||||
|
config: true,
|
||||||
|
type:Number,
|
||||||
|
default:1,
|
||||||
|
choices:["Mini","Normal or Mobile","XL"],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Playlist soundboard
|
||||||
|
*/
|
||||||
|
game.settings.register(MODULE.moduleName,'playlistMethod', {
|
||||||
|
name: "Playlist play method",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type:Number,
|
||||||
|
default:0,
|
||||||
|
choices:["Default","One track per playlist","One track in total"],
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.registerMenu(MODULE.moduleName, 'playlistConfigMenu',{
|
||||||
|
name: "Playlist Config",
|
||||||
|
label: "Playlist Config",
|
||||||
|
type: playlistConfigForm,
|
||||||
|
restricted: true
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.register(MODULE.moduleName, 'selectedPlaylists', {
|
||||||
|
name: "selectedPlaylists",
|
||||||
|
scope: "world",
|
||||||
|
type: Object,
|
||||||
|
default: {a: "None",b: "None",c: "none",d: "none",e: "none",f: "none",g: "none",h: "none",i: "none"},
|
||||||
|
config: false
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Macro Board
|
||||||
|
*/
|
||||||
|
game.settings.registerMenu(MODULE.moduleName, 'macroConfigMenu',{
|
||||||
|
name: "MaterialDeck.Sett.MacroConfig",
|
||||||
|
label: "MaterialDeck.Sett.MacroConfig",
|
||||||
|
type: macroConfigForm,
|
||||||
|
restricted: true
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.register(MODULE.moduleName, 'macroSettings', {
|
||||||
|
name: "macroSettings",
|
||||||
|
scope: "world",
|
||||||
|
type: Object,
|
||||||
|
config: false
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.register(MODULE.moduleName, 'macroArgs', {
|
||||||
|
name: "macroArgs",
|
||||||
|
scope: "world",
|
||||||
|
type: Object,
|
||||||
|
config: false
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Soundboard
|
||||||
|
*/
|
||||||
|
game.settings.register(MODULE.moduleName, 'soundboardSettings', {
|
||||||
|
name: "soundboardSettings",
|
||||||
|
scope: "world",
|
||||||
|
type: Object,
|
||||||
|
default: "None",
|
||||||
|
config: false
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.registerMenu(MODULE.moduleName, 'soundboardConfigMenu',{
|
||||||
|
name: "MaterialDeck.Sett.SoundboardConfig",
|
||||||
|
label: "MaterialDeck.Sett.SoundboardConfig",
|
||||||
|
type: soundboardConfigForm,
|
||||||
|
restricted: true
|
||||||
|
});
|
||||||
|
}
|
||||||
161
src/soundboard.js
Normal file
161
src/soundboard.js
Normal file
@@ -0,0 +1,161 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {streamDeck} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class SoundboardControl{
|
||||||
|
constructor(){
|
||||||
|
this.offset = 0;
|
||||||
|
this.activeSounds = [];
|
||||||
|
for (let i=0; i<64; i++)
|
||||||
|
this.activeSounds[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateAll(){
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'soundboard') continue;
|
||||||
|
await this.update(data.settings,data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
update(settings,context){
|
||||||
|
let mode = settings.soundboardMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
|
||||||
|
let txt = "";
|
||||||
|
let src = "";
|
||||||
|
let background = "#000000";
|
||||||
|
|
||||||
|
if (mode == 0){ //play sound
|
||||||
|
let soundNr = parseInt(settings.soundNr);
|
||||||
|
if (isNaN(soundNr)) soundNr = 1;
|
||||||
|
soundNr--;
|
||||||
|
soundNr += this.offset;
|
||||||
|
|
||||||
|
let soundboardSettings = game.settings.get(MODULE.moduleName, 'soundboardSettings');
|
||||||
|
|
||||||
|
let onColor = soundboardSettings.colorOn[soundNr];
|
||||||
|
let offColor = soundboardSettings.colorOff[soundNr];
|
||||||
|
|
||||||
|
background = onColor;
|
||||||
|
let ring = 2;
|
||||||
|
if (this.activeSounds[soundNr]==false) {
|
||||||
|
background = offColor;
|
||||||
|
ring = 1;
|
||||||
|
}
|
||||||
|
if (settings.displayName) txt = soundboardSettings.name[soundNr];
|
||||||
|
if (settings.displayIcon) src = soundboardSettings.img[soundNr];
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
streamDeck.setIcon(1,context,src,background,ring,background);
|
||||||
|
}
|
||||||
|
else if (mode == 1) { //Offset
|
||||||
|
src = "";
|
||||||
|
let onBackground = settings.onBackground;
|
||||||
|
if (onBackground == undefined) onBackground = '#00FF00';
|
||||||
|
let offBackground = settings.offBackground;
|
||||||
|
if (offBackground == undefined) offBackground = '#000000';
|
||||||
|
|
||||||
|
let offset = parseInt(settings.offset);
|
||||||
|
if (isNaN(offset)) offset = 0;
|
||||||
|
if (offset == this.offset) background = onBackground;
|
||||||
|
else background = offBackground;
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
streamDeck.setIcon(1,context,src,background);
|
||||||
|
}
|
||||||
|
else if (mode == 2) { //Stop all sounds
|
||||||
|
let src = 'action/images/soundboard/stop.png';
|
||||||
|
streamDeck.setIcon(0,context,src,settings.background);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressDown(settings){
|
||||||
|
let mode = settings.soundboardMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
if (mode == 0) { //Play sound
|
||||||
|
let soundNr = parseInt(settings.soundNr);
|
||||||
|
if (isNaN(soundNr)) soundNr = 1;
|
||||||
|
soundNr--;
|
||||||
|
soundNr += this.offset;
|
||||||
|
|
||||||
|
const playMode = game.settings.get(MODULE.moduleName,'soundboardSettings').mode[soundNr];
|
||||||
|
|
||||||
|
let repeat = false;
|
||||||
|
if (playMode > 0) repeat = true;
|
||||||
|
let play = false;
|
||||||
|
if (this.activeSounds[soundNr] == false) play = true;
|
||||||
|
this.playSound(soundNr,repeat,play);
|
||||||
|
}
|
||||||
|
else if (mode == 1) { //Offset
|
||||||
|
let offset = parseInt(settings.offset);
|
||||||
|
if (isNaN(offset)) offset = 0;
|
||||||
|
this.offset = offset;
|
||||||
|
this.updateAll();
|
||||||
|
}
|
||||||
|
else { //Stop All Sounds
|
||||||
|
for (let i=0; i<64; i++) {
|
||||||
|
if (this.activeSounds[i] != false){
|
||||||
|
this.playSound(i,false,false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPressUp(settings){
|
||||||
|
let mode = settings.soundboardMode;
|
||||||
|
if (mode == undefined) mode = 0;
|
||||||
|
if (mode != 0) return;
|
||||||
|
let soundNr = parseInt(settings.soundNr);
|
||||||
|
if (isNaN(soundNr)) soundNr = 1;
|
||||||
|
soundNr--;
|
||||||
|
soundNr += this.offset;
|
||||||
|
|
||||||
|
const playMode = game.settings.get(MODULE.moduleName,'soundboardSettings').mode[soundNr];
|
||||||
|
|
||||||
|
if (playMode == 2)
|
||||||
|
this.playSound(soundNr,false,false);
|
||||||
|
}
|
||||||
|
|
||||||
|
playSound(soundNr,repeat,play){
|
||||||
|
let trackId = game.settings.get(MODULE.moduleName,'soundboardSettings').sounds[soundNr];
|
||||||
|
let volume = game.settings.get(MODULE.moduleName,'soundboardSettings').volume[soundNr]/100;
|
||||||
|
volume = AudioHelper.inputToVolume(volume);
|
||||||
|
if (trackId == "" || trackId == undefined) return;
|
||||||
|
let payload = {
|
||||||
|
"msgType": "playSound",
|
||||||
|
"trackNr": soundNr,
|
||||||
|
"repeat": repeat,
|
||||||
|
"play": play,
|
||||||
|
"volume": volume
|
||||||
|
};
|
||||||
|
game.socket.emit(`module.MaterialDeck`, payload);
|
||||||
|
if (play){
|
||||||
|
let trackId = game.settings.get(MODULE.moduleName,'soundboardSettings').sounds[soundNr];
|
||||||
|
let playlistId = game.settings.get(MODULE.moduleName,'soundboardSettings').playlist;
|
||||||
|
let sounds = game.playlists.entities.find(p => p._id == playlistId).data.sounds;
|
||||||
|
let sound = sounds.find(p => p._id == trackId);
|
||||||
|
if (sound == undefined){
|
||||||
|
this.activeSounds[soundNr] = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
volume *= game.settings.get("core", "globalInterfaceVolume");
|
||||||
|
let src = sound.path;
|
||||||
|
|
||||||
|
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
|
||||||
|
if (repeat == false){
|
||||||
|
this.activeSounds[soundNr] = false;
|
||||||
|
this.updateAll();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onstop: (id)=>{
|
||||||
|
this.activeSounds[soundNr] = false;
|
||||||
|
this.updateAll();
|
||||||
|
}});
|
||||||
|
howl.play();
|
||||||
|
this.activeSounds[soundNr] = howl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.activeSounds[soundNr].stop();
|
||||||
|
this.activeSounds[soundNr] = false;
|
||||||
|
}
|
||||||
|
this.updateAll();
|
||||||
|
}
|
||||||
|
}
|
||||||
297
src/streamDeck.js
Normal file
297
src/streamDeck.js
Normal file
@@ -0,0 +1,297 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class StreamDeck{
|
||||||
|
constructor() {
|
||||||
|
this.pluginId;
|
||||||
|
this.tokenHealthContext;
|
||||||
|
this.tokenNameContext;
|
||||||
|
this.tokenACContext;
|
||||||
|
this.buttonContext = [];
|
||||||
|
for (let i=0; i<23; i++){
|
||||||
|
this.buttonContext[i] = undefined;
|
||||||
|
}
|
||||||
|
this.playlistTrackBuffer = [];
|
||||||
|
this.playlistSelector = 0;
|
||||||
|
this.trackSelector = 0;
|
||||||
|
for (let i=0; i<23; i++)
|
||||||
|
this.playlistTrackBuffer[i] = {state: 3, name: ""};
|
||||||
|
this.playlistBuffer = [];
|
||||||
|
for (let i=0; i<3; i++)
|
||||||
|
this.playlistBuffer[i] = {state: 3, name: ""};
|
||||||
|
this.counter = 0;
|
||||||
|
|
||||||
|
let canvasBox = document.createElement('div');
|
||||||
|
canvasBox.id = 'sdCanvasBox';
|
||||||
|
document.body.appendChild(canvasBox); // adds the canvas to the body element
|
||||||
|
}
|
||||||
|
|
||||||
|
setScreen(action){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
setContext(action,context,coordinates = {column:0,row:0},settings){
|
||||||
|
const data = {
|
||||||
|
context: context,
|
||||||
|
action: action,
|
||||||
|
settings: settings
|
||||||
|
}
|
||||||
|
let num = coordinates.column + coordinates.row*8;
|
||||||
|
this.buttonContext[num] = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
clearContext(action,coordinates = {column:0,row:0}){
|
||||||
|
let num = coordinates.column + coordinates.row*8;
|
||||||
|
this.buttonContext[num] = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
formatTitle(txt){
|
||||||
|
let txtArray = txt.split(" ");
|
||||||
|
let txtNew = "";
|
||||||
|
for (let i=0; i<txtArray.length; i++){
|
||||||
|
let txtNewPart = txtArray[i];
|
||||||
|
if (i<txtArray.length-1 && txtArray[i].length + txtArray[i+1].length < 8) {
|
||||||
|
txtNewPart = txtArray[i] + " " + txtArray[i+1];
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (txtNew.length > 0)
|
||||||
|
txtNew += "\n";
|
||||||
|
txtNew += txtNewPart;
|
||||||
|
}
|
||||||
|
return txtNew;
|
||||||
|
}
|
||||||
|
|
||||||
|
setTitle(txt,context){
|
||||||
|
txt = this.formatTitle(txt);
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
if (this.buttonContext[i] == undefined) continue;
|
||||||
|
if (this.buttonContext[i].context == context) {
|
||||||
|
if (this.buttonContext[i].txt != undefined)
|
||||||
|
if (this.buttonContext[i].txt == txt)
|
||||||
|
return;
|
||||||
|
this.buttonContext[i].txt = txt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let msg = {
|
||||||
|
event: 'setTitle',
|
||||||
|
context: context,
|
||||||
|
payload: {
|
||||||
|
title: txt,
|
||||||
|
target: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MODULE.sendWS(JSON.stringify(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
setColor(context,color = '#000000'){
|
||||||
|
let msg = {
|
||||||
|
event: 'setIcon',
|
||||||
|
context: context,
|
||||||
|
url: '',
|
||||||
|
format: 'color',
|
||||||
|
background: color
|
||||||
|
};
|
||||||
|
MODULE.sendWS(JSON.stringify(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
setImage(image,context){
|
||||||
|
//var image = "data:image/svg+xml;charset=utf8,<?xml version=\"1.0\" encoding=\"iso-8859-1\"?><!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --><svg version=\"1.1\" id=\"Capa_1\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0px\" y=\"0px\" viewBox=\"0 0 288 288\" style=\"enable-background:new 0 0 288 288;\" xml:space=\"preserve\"> <style> .text { font-family: sans-serif; fill: red; font-size: 10em; } </style><g> <text x=\"0px\" y=\"100px\" class=\"text\">GPUUTILIZATION</text></g></svg>";
|
||||||
|
|
||||||
|
var json = {
|
||||||
|
event: "setImage",
|
||||||
|
context: context,
|
||||||
|
payload: {
|
||||||
|
image: "" + image,
|
||||||
|
target: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MODULE.sendWS(JSON.stringify(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
setIcon(iconLocation, context,src,background = '#000000',ring=0,ringColor = "#000000"){
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
if (this.buttonContext[i] == undefined) continue;
|
||||||
|
if (this.buttonContext[i].context == context) {
|
||||||
|
if (this.buttonContext[i].icon == src && this.buttonContext[i].ring == ring && this.buttonContext[i].ringColor == ringColor && this.buttonContext[i].background == background && this.buttonContext[i].iconLocation == iconLocation)
|
||||||
|
return;
|
||||||
|
this.buttonContext[i].icon = src;
|
||||||
|
this.buttonContext[i].ring = ring;
|
||||||
|
this.buttonContext[i].ringColor = ringColor;
|
||||||
|
this.buttonContext[i].background = background;
|
||||||
|
this.buttonContext[i].iconLocation = iconLocation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let split = src.split('.');
|
||||||
|
let format = split[1];
|
||||||
|
split = src.split(' ');
|
||||||
|
if (split[0] == 'fas' || split[0] == 'far' || split[0] == 'fal' || split[0] == 'fad') format = 'icon';
|
||||||
|
let msg = {
|
||||||
|
event: 'setIcon',
|
||||||
|
context: context,
|
||||||
|
url: src,
|
||||||
|
format: format,
|
||||||
|
background: background,
|
||||||
|
ring: ring,
|
||||||
|
ringColor: ringColor
|
||||||
|
};
|
||||||
|
if (iconLocation == 0){
|
||||||
|
MODULE.sendWS(JSON.stringify(msg));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
this.getImage(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(state,context,action){
|
||||||
|
let msg = {
|
||||||
|
event: 'setStateCustom',
|
||||||
|
context: context,
|
||||||
|
action: action,
|
||||||
|
state: state
|
||||||
|
};
|
||||||
|
MODULE.sendWS(JSON.stringify(msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
setProfile(action,device){
|
||||||
|
let profile;
|
||||||
|
if (action == 'playlistcontrol')
|
||||||
|
profile = 'MaterialDeck-Playlist'
|
||||||
|
var json = {
|
||||||
|
"source": 1,
|
||||||
|
"event": "switchToProfile",
|
||||||
|
"context": this.pluginId,
|
||||||
|
"device": device,
|
||||||
|
"payload": {
|
||||||
|
"profile": profile
|
||||||
|
}
|
||||||
|
};
|
||||||
|
MODULE.sendWS(JSON.stringify(json));
|
||||||
|
}
|
||||||
|
|
||||||
|
setPluginId(id){
|
||||||
|
this.pluginId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFAChar = function (name) {
|
||||||
|
var elm = document.createElement('i');
|
||||||
|
elm.className = name;
|
||||||
|
elm.style.display = 'none';
|
||||||
|
document.body.appendChild(elm);
|
||||||
|
var content = window.getComputedStyle(
|
||||||
|
elm, ':before'
|
||||||
|
).getPropertyValue('content')
|
||||||
|
//console.log(elm);
|
||||||
|
document.body.removeChild(elm);
|
||||||
|
return content;
|
||||||
|
};
|
||||||
|
|
||||||
|
getImage(data){
|
||||||
|
if (data == undefined)
|
||||||
|
return;
|
||||||
|
console.log('image',data)
|
||||||
|
const context = data.context;
|
||||||
|
var url = data.url;
|
||||||
|
const format = data.format;
|
||||||
|
var background = data.background;
|
||||||
|
|
||||||
|
let BGvalid = true;
|
||||||
|
if (background.length != 7) BGvalid = false;
|
||||||
|
if (background[0] != '#') BGvalid = false;
|
||||||
|
for (let i=1; i<background.length; i++)
|
||||||
|
if(isNaN(parseInt(background[i],16)))
|
||||||
|
BGvalid = false;
|
||||||
|
if (BGvalid == false) background = '#000000';
|
||||||
|
|
||||||
|
let canvas;
|
||||||
|
let canvasId = 'sdCanvas' + this.counter;
|
||||||
|
canvas = document.getElementById(canvasId);
|
||||||
|
if (canvas == null){
|
||||||
|
canvas = document.createElement('canvas');
|
||||||
|
canvas.id = canvasId;
|
||||||
|
canvas.width="144";
|
||||||
|
canvas.height="144";
|
||||||
|
canvas.style="background-color:transparent";
|
||||||
|
document.getElementById('sdCanvasBox').appendChild(canvas); // adds the canvas to #someBox
|
||||||
|
}
|
||||||
|
this.counter++;
|
||||||
|
if (this.counter > 31) this.counter = 0;
|
||||||
|
|
||||||
|
let ctx = canvas.getContext("2d");
|
||||||
|
ctx.filter = "none";
|
||||||
|
|
||||||
|
let margin = 0;
|
||||||
|
|
||||||
|
if (data.ring != undefined && data.ring > 0){
|
||||||
|
ctx.fillStyle = background;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
margin = 10;
|
||||||
|
if (data.ring == 2) {
|
||||||
|
ctx.fillStyle = data.ringColor;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillStyle = background;
|
||||||
|
ctx.fillRect(margin, margin, canvas.width-2*margin, canvas.height-2*margin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ctx.fillStyle = background;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
}
|
||||||
|
if (format == 'icon' && url != ""){
|
||||||
|
ctx.font = '600 90px "Font Awesome 5 Free"';
|
||||||
|
ctx.fillStyle = "gray";
|
||||||
|
var elm = document.createElement('i');
|
||||||
|
elm.className = url;
|
||||||
|
elm.style.display = 'none';
|
||||||
|
canvas.appendChild(elm);
|
||||||
|
var content = window.getComputedStyle(
|
||||||
|
elm, ':before'
|
||||||
|
).getPropertyValue('content')
|
||||||
|
//console.log(content[1]);
|
||||||
|
canvas.removeChild(elm);
|
||||||
|
ctx.fillText(content[1], 35, 105);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format != 'jpg' && format != 'jpeg' && format != 'png' && format != 'webm' && format != 'webp' && format != 'gif' && format != 'svg') url = "modules/MaterialDeck/img/transparant.png";
|
||||||
|
if (url == "") url = "modules/MaterialDeck/img/transparant.png"
|
||||||
|
//console.log(url);
|
||||||
|
let resImageURL = url;
|
||||||
|
|
||||||
|
let img = new Image();
|
||||||
|
img.onload = () => {
|
||||||
|
if (format == 'color') ctx.filter = "opacity(0)";
|
||||||
|
//ctx.filter = "brightness(0) saturate(100%) invert(38%) sepia(62%) saturate(2063%) hue-rotate(209deg) brightness(90%) contrast(95%)";
|
||||||
|
var imageAspectRatio = img.width / img.height;
|
||||||
|
var canvasAspectRatio = canvas.width / canvas.height;
|
||||||
|
var renderableHeight, renderableWidth, xStart, yStart;
|
||||||
|
|
||||||
|
// If image's aspect ratio is less than canvas's we fit on height
|
||||||
|
// and place the image centrally along width
|
||||||
|
if(imageAspectRatio < canvasAspectRatio) {
|
||||||
|
renderableHeight = canvas.height;
|
||||||
|
renderableWidth = img.width * (renderableHeight / img.height);
|
||||||
|
xStart = (canvas.width - renderableWidth) / 2;
|
||||||
|
yStart = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If image's aspect ratio is greater than canvas's we fit on width
|
||||||
|
// and place the image centrally along height
|
||||||
|
else if(imageAspectRatio > canvasAspectRatio) {
|
||||||
|
renderableWidth = canvas.width
|
||||||
|
renderableHeight = img.height * (renderableWidth / img.width);
|
||||||
|
xStart = 0;
|
||||||
|
yStart = (canvas.height - renderableHeight) / 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Happy path - keep aspect ratio
|
||||||
|
else {
|
||||||
|
renderableHeight = canvas.height;
|
||||||
|
renderableWidth = canvas.width;
|
||||||
|
xStart = 0;
|
||||||
|
yStart = 0;
|
||||||
|
}
|
||||||
|
ctx.drawImage(img, xStart+margin, yStart+margin, renderableWidth - 2*margin, renderableHeight - 2*margin);
|
||||||
|
var dataURL = canvas.toDataURL();
|
||||||
|
this.setImage(dataURL,data.context);
|
||||||
|
};
|
||||||
|
img.src = resImageURL;
|
||||||
|
}
|
||||||
|
}
|
||||||
117
src/token.js
Normal file
117
src/token.js
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
import * as MODULE from "../MaterialDeck.js";
|
||||||
|
import {streamDeck} from "../MaterialDeck.js";
|
||||||
|
|
||||||
|
export class TokenControl{
|
||||||
|
constructor(){
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(tokenId){
|
||||||
|
console.log('tokenId',tokenId)
|
||||||
|
for (let i=0; i<32; i++){
|
||||||
|
let data = streamDeck.buttonContext[i];
|
||||||
|
if (data == undefined || data.action != 'token') continue;
|
||||||
|
await this.pushData(tokenId,data.settings,data.context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pushData(tokenId,settings,context,ring=0,ringColor='#000000'){
|
||||||
|
console.log('tk',tokenId,settings)
|
||||||
|
let name = false;
|
||||||
|
let icon = false;
|
||||||
|
let type = 0;
|
||||||
|
let background = "#000000";
|
||||||
|
|
||||||
|
if (settings.displayIcon) icon = true;
|
||||||
|
if (settings.displayName) name = true;
|
||||||
|
if (settings.stats != undefined) type = settings.stats;
|
||||||
|
if (settings.background) background = settings.background;
|
||||||
|
|
||||||
|
let tokenName = "";
|
||||||
|
let hp = "";
|
||||||
|
let AC = "";
|
||||||
|
let speed = "";
|
||||||
|
let initiative = "";
|
||||||
|
let txt = "";
|
||||||
|
let iconSrc = "";
|
||||||
|
if (tokenId != undefined) {
|
||||||
|
let token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
|
||||||
|
tokenName = token.data.name;
|
||||||
|
iconSrc += token.data.img;
|
||||||
|
let actor = canvas.tokens.children[0].children.find(p => p.id == tokenId).actor;
|
||||||
|
let system = game.system.id;
|
||||||
|
if (system == 'dnd5e'){
|
||||||
|
let attributes = actor.data.data.attributes;
|
||||||
|
let hpCurrent = attributes.hp.value;
|
||||||
|
let hpMax = attributes.hp.max;
|
||||||
|
hp = hpCurrent + "/" + hpMax;
|
||||||
|
AC = attributes.ac.value;
|
||||||
|
|
||||||
|
if (attributes.speed._deprecated){
|
||||||
|
if (attributes.movement.burrow > 0) speed += attributes.movement.burrow + attributes.movement.units + " burrow";
|
||||||
|
if (attributes.movement.climb > 0) {
|
||||||
|
if (speed.length > 0) speed += '\n';
|
||||||
|
speed += attributes.movement.climb + attributes.movement.units + " climb";
|
||||||
|
}
|
||||||
|
if (attributes.movement.fly > 0) {
|
||||||
|
if (speed.length > 0) speed += '\n';
|
||||||
|
speed += attributes.movement.fly + attributes.movement.units + " fly";
|
||||||
|
}
|
||||||
|
if (attributes.movement.hover > 0) {
|
||||||
|
if (speed.length > 0) speed += '\n';
|
||||||
|
speed += attributes.movement.hover + attributes.movement.units + " hover";
|
||||||
|
}
|
||||||
|
if (attributes.movement.swim > 0) {
|
||||||
|
if (speed.length > 0) speed += '\n';
|
||||||
|
speed += attributes.movement.swim + attributes.movement.units + " swim";
|
||||||
|
}
|
||||||
|
if (attributes.movement.walk > 0) {
|
||||||
|
if (speed.length > 0) speed += '\n';
|
||||||
|
speed += attributes.movement.walk + attributes.movement.units + " walk";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
speed = attributes.speed.value;
|
||||||
|
if (attributes.speed.special.length > 0) speed + "\n" + attributes.speed.special;
|
||||||
|
}
|
||||||
|
initiative = attributes.init.total;
|
||||||
|
}
|
||||||
|
else return;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
iconSrc += "";
|
||||||
|
}
|
||||||
|
if (icon) streamDeck.setIcon(1,context,iconSrc,background,ring,ringColor);
|
||||||
|
|
||||||
|
if (name) txt += tokenName;
|
||||||
|
if (name && type > 0) txt += "\n";
|
||||||
|
if (type == 1) txt += hp;
|
||||||
|
else if (type == 2) txt += AC;
|
||||||
|
else if (type == 3) txt += speed;
|
||||||
|
else if (type == 4) txt += initiative;
|
||||||
|
streamDeck.setTitle(txt,context);
|
||||||
|
}
|
||||||
|
|
||||||
|
keyPress(settings){
|
||||||
|
if (MODULE.selectedTokenId == undefined) return;
|
||||||
|
const tokenId = MODULE.selectedTokenId;
|
||||||
|
|
||||||
|
let onClick = settings.onClick;
|
||||||
|
if (onClick == undefined) conClick = 0;
|
||||||
|
|
||||||
|
const token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
|
||||||
|
if (token == undefined) return;
|
||||||
|
|
||||||
|
if (onClick == 0) //Do nothing
|
||||||
|
return;
|
||||||
|
else if (onClick == 1){ //center on token
|
||||||
|
let location = token.getCenter(token.x,token.y);
|
||||||
|
canvas.animatePan(location);
|
||||||
|
}
|
||||||
|
else if (onClick == 2){ //Open character sheet
|
||||||
|
token.actor.sheet.render(true);
|
||||||
|
}
|
||||||
|
else { //Open token config
|
||||||
|
token.sheet._render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
45
templates/macroConfig.html
Normal file
45
templates/macroConfig.html
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<form autocomplete="off" onsubmit="event.preventDefault()">
|
||||||
|
<style>
|
||||||
|
.boxed {
|
||||||
|
border: 1px solid black ;
|
||||||
|
border-radius: 5px ;
|
||||||
|
width: 100px;
|
||||||
|
height: {{height}}px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
{{#each macroData}}
|
||||||
|
<div class="form-group">
|
||||||
|
{{#each this.dataThis}}
|
||||||
|
<div class="boxed" style="padding: 5px; margin:2px">
|
||||||
|
<div style="text-align:center;">
|
||||||
|
{{localize "MaterialDeck.Macro.Macro"}} {{this.iteration}}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<select name="macros" class="macros-select" default="" style="max-width:140px;">
|
||||||
|
{{#select this.macro}}
|
||||||
|
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||||
|
{{#each macros}}
|
||||||
|
<option value="{{this._id}}">{{this.name}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{#if this.furnace}}
|
||||||
|
<label>{{localize "MaterialDeck.Macro.FurnaceArgs"}}</label>
|
||||||
|
<input type="text" name="args" value="{{this.args}}">
|
||||||
|
{{/if}}
|
||||||
|
|
||||||
|
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:10px">
|
||||||
|
<label style="flex:1">{{localize "MaterialDeck.Macro.Background"}}</label>
|
||||||
|
<input style="flex:1" type="color" name="colorPicker" data-dtype="String" value="{{this.color}}">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
<button type="submit" name="submit">
|
||||||
|
<i class="far fa-save"></i> {{localize "MaterialDeck.Playlist.Save"}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
36
templates/playlistConfig.html
Normal file
36
templates/playlistConfig.html
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<form autocomplete="off" onsubmit="event.preventDefault()">
|
||||||
|
<div >
|
||||||
|
<h2>{{localize "MaterialDeck.Playlist.Playmethod.Header"}}</h2>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "MaterialDeck.Playlist.Playmethod.Label"}}</label>
|
||||||
|
<select name="playMethod" class="playMethod" default="">
|
||||||
|
{{#select playMethod}}
|
||||||
|
<option value="0">{{localize "MaterialDeck.Playlist.Playmethod.Unrestricted"}}</option>
|
||||||
|
<option value="1">{{localize "MaterialDeck.Playlist.Playmethod.OneTrackPlaylist"}}</option>
|
||||||
|
<option value="2">{{localize "MaterialDeck.Playlist.Playmethod.OneTrackTotal"}}</option>
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h2>{{localize "MaterialDeck.Playlist.Playlists"}}</h2>
|
||||||
|
</div>
|
||||||
|
{{#each playlistData}}
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "MaterialDeck.Playlist.Playlist"}} {{this.iteration}}</label>
|
||||||
|
<select name="selectedPlaylist" class="playlist-select" default="">
|
||||||
|
{{#select this.playlist}}
|
||||||
|
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||||
|
{{#each this.playlists}}
|
||||||
|
<option value="{{this._id}}">{{this.name}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
|
||||||
|
<button type="submit" name="submit">
|
||||||
|
<i class="far fa-save"></i> {{localize "MaterialDeck.Playlist.Save"}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
84
templates/soundboardConfig.html
Normal file
84
templates/soundboardConfig.html
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
<form autocomplete="off" onsubmit="event.preventDefault()">
|
||||||
|
<style>
|
||||||
|
.boxed {
|
||||||
|
border: 1px solid black ;
|
||||||
|
border-radius: 5px ;
|
||||||
|
width: 100px;
|
||||||
|
height: 255px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="form-group">
|
||||||
|
<label>{{localize "MaterialDeck.Playlist.Playlist"}} </label>
|
||||||
|
<select name="playlist" class="playlist-select" default="" style="max-width:200px;">
|
||||||
|
{{#select playlist}}
|
||||||
|
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||||
|
{{#each playlists}}
|
||||||
|
<option value="{{this._id}}">{{this.name}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
{{#each soundData}}
|
||||||
|
<div class="form-group">
|
||||||
|
{{#each this.dataThis}}
|
||||||
|
<div class="boxed" style="padding: 5px; margin:2px">
|
||||||
|
<div style="text-align:center;">
|
||||||
|
{{localize "MaterialDeck.Soundboard.Sound"}} {{this.iteration}}
|
||||||
|
</div>
|
||||||
|
<div style="text-align:center;">
|
||||||
|
{{localize "MaterialDeck.Name"}}
|
||||||
|
</div>
|
||||||
|
<input type="text" name="name" value="{{this.name}}">
|
||||||
|
<div style="text-align:center;">
|
||||||
|
{{localize "MaterialDeck.Soundboard.Sound"}}
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<select name="sounds" class="sounds-select" default="" style="width:132px;" id="soundSelect{{this.iteration}}">
|
||||||
|
{{#select this.sound}}
|
||||||
|
<option value="">{{localize "MaterialDeck.Playlist.None"}}</option>
|
||||||
|
{{#each sounds}}
|
||||||
|
<option value="{{this._id}}">{{this.name}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div style="text-align:center;">
|
||||||
|
{{localize "MaterialDeck.Soundboard.Icon"}}
|
||||||
|
</div>
|
||||||
|
<div class="form-fields">
|
||||||
|
<button type="button" class="file-picker" data-type="image" data-target="img{{this.iteration}}" title="Browse Files" tabindex="-1">
|
||||||
|
<i class="fas fa-file-import fa-fw"></i>
|
||||||
|
</button>
|
||||||
|
<input class="image" type="text" name="img{{this.iteration}}" id="imgPath{{this.iteration}}" placeholder="path/image.png" value={{this.imgPath}}>
|
||||||
|
</div>
|
||||||
|
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:5px">
|
||||||
|
<label style="flex:1">{{localize "MaterialDeck.Soundboard.On"}} </label>
|
||||||
|
<input style="flex:1" type="color" id="colorOn{{this.iteration}}" name="colorOn" style="flex:4" data-dtype="String" value="{{this.colorOn}}">
|
||||||
|
<label style="flex:1"> {{localize "MaterialDeck.Soundboard.Off"}} </label>
|
||||||
|
<input style="flex:1" type="color" id="colorOff{{this.iteration}}" name="colorOff" style="flex:4" data-dtype="String" value="{{this.colorOff}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group options">
|
||||||
|
<label>{{localize "MaterialDeck.Soundboard.Playback"}}</label>
|
||||||
|
<select name="mode" style="flex:1">
|
||||||
|
{{#select this.mode}}
|
||||||
|
<option value="0">{{localize "MaterialDeck.Soundboard.Once"}}</option>
|
||||||
|
<option value="1">{{localize "MaterialDeck.Soundboard.Repeat"}}</option>
|
||||||
|
<option value="2">{{localize "MaterialDeck.Soundboard.Hold"}}</option>
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group options">
|
||||||
|
<label>{{localize "MaterialDeck.Soundboard.Volume"}}</label>
|
||||||
|
<input type="range" min="0" max="100" value={{this.volume}} class="slider" name="volume" id="volume{{this.iteration}}">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
{{/each}}
|
||||||
|
<button type="submit" name="submit">
|
||||||
|
<i class="far fa-save"></i> {{localize "MaterialDeck.Playlist.Save"}}
|
||||||
|
</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
Reference in New Issue
Block a user