This commit is contained in:
CDeenen
2021-04-13 02:30:10 +02:00
parent cc9bcf4770
commit 1552ae6fe8
19 changed files with 538 additions and 170 deletions

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck, tokenControl} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class CombatTracker{
constructor(){
@@ -28,7 +29,7 @@ export class CombatTracker{
if (mode == 'combatants'){
if (MODULE.getPermission('COMBAT','DISPLAY_COMBATANTS') == false) {
streamDeck.noPermission(context);
streamDeck.noPermission(context,false,"combat tracker");
return;
}
if (combat != null && combat != undefined && combat.turns.length != 0){
@@ -39,7 +40,7 @@ export class CombatTracker{
const combatant = initiativeOrder[nr]
if (combatant != undefined){
const tokenId = combatant.tokenId;
const tokenId = compatibleCore("0.8.1") ? combatant.data.tokenId : combatant.tokenId;
tokenControl.pushData(tokenId,settings,context,combatantState,'#cccc00');
return;
}
@@ -59,7 +60,7 @@ export class CombatTracker{
return;
}
if (combat != null && combat != undefined && combat.started){
const tokenId = combat.combatant.tokenId;
const tokenId = compatibleCore("0.8.1") ? combat.combatant.data.tokenId : combat.combatant.tokenId;
tokenControl.pushData(tokenId,settings,context);
}
else {
@@ -168,7 +169,7 @@ export class CombatTracker{
return;
}
if (game.combat.started == false) return;
if (ctFunction == 'nextTurn') game.combat.nextTurn();
else if (ctFunction == 'prevTurn') game.combat.previousTurn();
else if (ctFunction == 'nextRound') game.combat.nextRound();
@@ -185,12 +186,12 @@ export class CombatTracker{
if (nr == undefined || nr < 1) nr = 0;
const combatant = initiativeOrder[nr]
if (combatant == undefined) return;
tokenId = combatant.tokenId;
tokenId = compatibleCore("0.8.1") ? combatant.data.tokenId : combatant.tokenId;
}
}
else if (mode == 'currentCombatant')
if (combat != null && combat != undefined && combat.started)
tokenId = combat.combatant.tokenId;
tokenId = compatibleCore("0.8.1") ? combat.combatant.data.tokenId : combat.combatant.tokenId;
let token = (canvas.tokens.children[0] != undefined) ? canvas.tokens.children[0].children.find(p => p.id == tokenId) : undefined;
if (token == undefined) return;

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class MacroControl{
constructor(){
@@ -58,6 +59,11 @@ export class MacroControl{
ring = 0;
}
}
else if (mode == 'name') { //macro by name
const macroName = settings.macroNumber;
const macro = game.macros.getName(macroName);
macroId = macro?.id;
}
else { //Macro Hotbar
if ((MODULE.getPermission('MACRO','HOTBAR') == false )) {
streamDeck.noPermission(context);
@@ -71,10 +77,7 @@ export class MacroControl{
else
macros = game.macros.apps[0].macros;
if (macroNumber > 9) macroNumber = 0;
for (let j=0; j<10; j++){
if (macros[j].key == macroNumber)
macroId = (macros[j].macro == null) ? undefined : macros[j].macro._id;
}
macroId = game.macros.apps[0].macros.find(m => m.key == macroNumber).macro?.id
}
}
@@ -87,7 +90,10 @@ export class MacroControl{
if (MODULE.hotbarUses && displayUses) uses = await this.getUses(macro);
}
}
else {
if (displayName) name = "";
if (displayIcon) src = "modules/MaterialDeck/img/black.png";
}
streamDeck.setIcon(context,src,{background:background,ring:ring,ringColor:ringColor,uses:uses});
streamDeck.setTitle(name,context);
@@ -130,12 +136,7 @@ export class MacroControl{
}
else {
if (macroNumber > 9) macroNumber = 0;
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;
}
}
macroId = game.macros.apps[0].macros.find(m => m.key == macroNumber).macro?.id
}
let macro = undefined;
let uses = undefined;
@@ -154,11 +155,44 @@ export class MacroControl{
const mode = settings.macroMode ? settings.macroMode : 'hotbar';
let macroNumber = settings.macroNumber;
if(macroNumber == undefined || isNaN(parseInt(macroNumber))) macroNumber = 0;
let target = settings.target ? settings.target : undefined;
//const targetActor = target.actor ? undefined : target;
//if (targetActor != undefined) target = undefined;
//let macroTarget = {
// token: target,
// actor: targetActor
//}
//console.log('target',macroTarget,mode);
if (mode == 'hotbar' || mode == 'visibleHotbar' || mode == 'customHotbar'){
if ((MODULE.getPermission('MACRO','HOTBAR') == false )) return;
this.executeHotbar(macroNumber,mode);
}
else if (mode == 'name') {
if ((MODULE.getPermission('MACRO','BY_NAME') == false )) return;
const macroName = settings.macroNumber;
const macro = game.macros.getName(macroName);
if (macro == undefined) return;
const args = settings.macroArgs ? settings.macroArgs : "";
let furnaceEnabled = false;
let furnace = game.modules.get("furnace");
if (furnace != undefined && furnace.active && compatibleCore("0.8.1")==false) furnaceEnabled = true;
if (args == "" || args == " ") furnaceEnabled = false;
if (furnaceEnabled == false) macro.execute({token:target});
else {
let chatData = {
user: game.user._id,
speaker: ChatMessage.getSpeaker(),
content: "/'" + macro.name + "' " + args
};
ChatMessage.create(chatData, {});
}
}
else {
if ((MODULE.getPermission('MACRO','MACROBOARD') == false )) return;
if (settings.macroBoardMode == 'offset') {
@@ -182,12 +216,7 @@ export class MacroControl{
}
else macros = game.macros.apps[0].macros;
if (macroNumber > 9) macroNumber = 0;
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;
}
}
macroId = game.macros.apps[0].macros.find(m => m.key == macroNumber).macro?.id
}
if (macroId == undefined) return;
let macro = game.macros.get(macroId);
@@ -206,7 +235,7 @@ export class MacroControl{
const args = game.settings.get(MODULE.moduleName,'macroSettings').args;
let furnaceEnabled = false;
let furnace = game.modules.get("furnace");
if (furnace != undefined && furnace.active) furnaceEnabled = true;
if (furnace != undefined && furnace.active && compatibleCore("0.8.1")==false) furnaceEnabled = true;
if (args == undefined || args[macroNumber] == undefined || args[macroNumber] == "") furnaceEnabled = false;
if (furnaceEnabled == false) macro.execute();
else {

View File

@@ -1,6 +1,16 @@
import * as MODULE from "../MaterialDeck.js";
import {macroControl,soundboard,playlistControl} from "../MaterialDeck.js";
export function compatibleCore(compatibleVersion){
let coreVersion = game.data.version;
coreVersion = coreVersion.split(".");
compatibleVersion = compatibleVersion.split(".");
if (compatibleVersion[0] > coreVersion[0]) return false;
if (compatibleVersion[1] > coreVersion[1]) return false;
if (compatibleVersion[2] > coreVersion[2]) return false;
return true;
}
export class playlistConfigForm extends FormApplication {
constructor(data, options) {
super(data, options);
@@ -17,7 +27,8 @@ export class playlistConfigForm extends FormApplication {
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.PlaylistConfig"),
template: "./modules/MaterialDeck/templates/playlistConfig.html",
classes: ["sheet"],
width: 500
width: 500,
height: "auto"
});
}
@@ -65,7 +76,7 @@ export class playlistConfigForm extends FormApplication {
}
return {
playlists: game.playlists.entities,
playlists: compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities,
numberOfPlaylists: numberOfPlaylists,
playlistData: playlistData,
playMode: playMode
@@ -171,7 +182,7 @@ export class macroConfigForm extends FormApplication {
let furnaceEnabled = false;
let height = 95;
let furnace = game.modules.get("furnace");
if (furnace != undefined && furnace.active) {
if (furnace != undefined && furnace.active && compatibleCore("0.8.1")==false) {
furnaceEnabled = true;
height += 50;
}
@@ -222,7 +233,7 @@ export class macroConfigForm extends FormApplication {
}
macroData.push({dataThis: macroThis});
}
return {
height: height,
macros: game.macros,
@@ -335,9 +346,11 @@ export class soundboardConfigForm extends FormApplication {
let playlists = [];
playlists.push({id:"none",name:game.i18n.localize("MaterialDeck.None")});
playlists.push({id:"FP",name:game.i18n.localize("MaterialDeck.FilePicker")})
for (let i=0; i<game.playlists.entities.length; i++){
playlists.push({id:game.playlists.entities[i]._id,name:game.playlists.entities[i].name});
}
const playlistArray = compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities;
for (let playlist of playlistArray)
playlists.push({id: playlist.id, name: playlist.name})
this.playlists = playlists;
//Check what SD model the user is using, and set the number of rows and columns to correspond
@@ -376,20 +389,30 @@ export class soundboardConfigForm extends FormApplication {
else if (this.settings.selectedPlaylists[iteration] == 'FP') selectedPlaylist = 'FP';
else {
//Get the playlist
const pl = game.playlists.entities.find(p => p._id == this.settings.selectedPlaylists[iteration]);
const playlistArray = compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities;
let pl = playlistArray.find(p => p.id == this.settings.selectedPlaylists[iteration])
if (pl == undefined){
selectedPlaylist = 'none';
sounds = [];
}
else {
//Add the sound name and id to the sounds array
for (let i=0; i<pl.sounds.length; i++)
sounds.push({
name: pl.sounds[i].name,
id: pl.sounds[i]._id
});
if (compatibleCore("0.8.1"))
for (let sound of pl.sounds.contents)
sounds.push({
name: sound.name,
id: sound.id
});
else {
for (let sound of pl.sounds)
sounds.push({
name: sound.name,
id: sound._id
});
}
//Get the playlist id
selectedPlaylist = pl._id;
selectedPlaylist = pl.id;
}
}
@@ -489,8 +512,9 @@ export class soundboardConfigForm extends FormApplication {
//Show the sound selector
document.querySelector(`#ss${iteration}`).style='';
const pl = game.playlists.entities.find(p => p._id == event.target.value);
selectedPlaylist = pl._id;
const playlistArray = compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities;
const pl = playlistArray.find(p => p.id == event.target.value)
selectedPlaylist = pl.id;
//Get the sound select element
let SSpicker = document.getElementById(`soundSelect${iteration}`);
@@ -504,12 +528,20 @@ export class soundboardConfigForm extends FormApplication {
optionNone.innerHTML = game.i18n.localize("MaterialDeck.None");
SSpicker.appendChild(optionNone);
for (let i=0; i<pl.sounds.length; i++){
let newOption = document.createElement('option');
newOption.value = pl.sounds[i]._id;
newOption.innerHTML = pl.sounds[i].name;
SSpicker.appendChild(newOption);
}
if (compatibleCore("0.8.1"))
for (let sound of pl.sounds.contents) {
let newOption = document.createElement('option');
newOption.value = sound.id;
newOption.innerHTML = sound.name;
SSpicker.appendChild(newOption);
}
else
for (let sound of pl.sounds) {
let newOption = document.createElement('option');
newOption.value = sound._id;
newOption.innerHTML = sound.name;
SSpicker.appendChild(newOption);
}
}
//Save the new playlist to this.settings, and update the settings

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class Move{
constructor(){
@@ -106,7 +107,9 @@ export class Move{
if (rotType == 'by') rotationVal = token.data.rotation + value;
else if (rotType == 'to') rotationVal = value;
token.update({rotation: rotationVal});
if (compatibleCore("0.8.1")) token.document.update({rotation: rotationVal});
else token.update({rotation: rotationVal});
//token.rotate(rotationVal,false)
}
}
@@ -140,7 +143,8 @@ export class Move{
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});
if (compatibleCore("0.8.1")) token.document.update({x:x,y:y});
else token.update({x:x,y:y});
};
moveCanvas(dir){

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class OtherControls{
constructor(){
@@ -7,37 +8,39 @@ export class OtherControls{
this.rollData = {};
}
async updateAll(){
async updateAll(options={}){
if (this.active == false) return;
for (let i=0; i<32; i++){
const data = streamDeck.buttonContext[i];
if (data == undefined || data.action != 'other') continue;
await this.update(data.settings,data.context);
await this.update(data.settings,data.context,options);
}
}
update(settings,context){
update(settings,context,options={}){
this.active = true;
const mode = settings.otherMode ? settings.otherMode : 'pause';
if (mode == 'pause') //pause
this.updatePause(settings,context);
this.updatePause(settings,context,options);
else if (mode == 'controlButtons') //control buttons
this.updateControl(settings,context);
this.updateControl(settings,context,options);
else if (mode == 'darkness') //darkness
this.updateDarkness(settings,context);
this.updateDarkness(settings,context,options);
else if (mode == 'rollDice') //roll dice
this.updateRollDice(settings,context);
this.updateRollDice(settings,context,options);
else if (mode == 'rollTables') //roll tables
this.updateRollTable(settings,context);
this.updateRollTable(settings,context,options);
else if (mode == 'sidebarTab') //open sidebar tab
this.updateSidebar(settings,context);
this.updateSidebar(settings,context,options);
else if (mode == 'compendiumBrowser') //open compendium browser
this.updateCompendiumBrowser(settings,context,options);
else if (mode == 'compendium') //open compendium
this.updateCompendium(settings,context);
this.updateCompendium(settings,context,options);
else if (mode == 'journal') //open journal
this.updateJournal(settings,context);
this.updateJournal(settings,context,options);
else if (mode == 'chatMessage')
this.updateChatMessage(settings,context);
this.updateChatMessage(settings,context,options);
}
keyPress(settings,context){
@@ -55,6 +58,8 @@ export class OtherControls{
this.keyPressRollTable(settings);
else if (mode == 'sidebarTab') //sidebar
this.keyPressSidebar(settings);
else if (mode == 'compendiumBrowser') //open compendium browser
this.keyPressCompendiumBrowser(settings);
else if (mode == 'compendium') //open compendium
this.keyPressCompendium(settings);
else if (mode == 'journal') //open journal
@@ -65,7 +70,7 @@ export class OtherControls{
//////////////////////////////////////////////////////////////////////////////////////////////////
updatePause(settings,context){
updatePause(settings,context,options={}){
if (MODULE.getPermission('OTHER','PAUSE') == false ) {
streamDeck.noPermission(context);
return;
@@ -97,20 +102,20 @@ export class OtherControls{
if (pauseFunction == 'pause'){ //Pause game
if (game.paused) return;
game.togglePause();
game.togglePause(true,true);
}
else if (pauseFunction == 'resume'){ //Resume game
if (game.paused == false) return;
game.togglePause();
game.togglePause(false,true);
}
else if (pauseFunction == 'toggle') { //toggle
game.togglePause();
game.togglePause(!game.paused,true);
}
}
//////////////////////////////////////////////////////////////////////////////////////////
updateControl(settings,context){
updateControl(settings,context,options={}){
if (MODULE.getPermission('OTHER','CONTROL') == false ) {
streamDeck.noPermission(context);
return;
@@ -291,7 +296,7 @@ export class OtherControls{
//////////////////////////////////////////////////////////////////////////////////////////
updateDarkness(settings,context){
updateDarkness(settings,context,options={}){
if (MODULE.getPermission('OTHER','DARKNESS') == false ) {
streamDeck.noPermission(context);
return;
@@ -337,7 +342,7 @@ export class OtherControls{
//////////////////////////////////////////////////////////////////////////////////////////
updateRollDice(settings,context){
updateRollDice(settings,context,options={}){
if (MODULE.getPermission('OTHER','DICE') == false ) {
streamDeck.noPermission(context);
return;
@@ -389,7 +394,7 @@ export class OtherControls{
//////////////////////////////////////////////////////////////////////////////////////////
updateRollTable(settings,context){
updateRollTable(settings,context,options={}){
const name = settings.rollTableName;
if (name == undefined) return;
if (MODULE.getPermission('OTHER','TABLES') == false ) {
@@ -474,17 +479,23 @@ export class OtherControls{
return icon;
}
updateSidebar(settings,context){
updateSidebar(settings,context,options={}){
if (MODULE.getPermission('OTHER','SIDEBAR') == false ) {
streamDeck.noPermission(context);
return;
}
const popOut = settings.sidebarPopOut ? settings.sidebarPopOut : false;
const sidebarTab = settings.sidebarTab ? settings.sidebarTab : 'chat';
const background = settings.background ? settings.background : '#000000';
const collapsed = ui.sidebar._collapsed;
const activeTab = ui.sidebar.activeTab;
const ringOffColor = settings.offRing ? settings.offRing : '#000000';
const ringOnColor = settings.onRing ? settings.onRing : '#00FF00';
const ringColor = (sidebarTab == 'collapse' && collapsed) ? ringOnColor : ringOffColor;
let ringColor = ringOffColor;
if (popOut && options.sidebarTab == sidebarTab) {
ringColor = options.renderPopout ? ringOnColor : ringOffColor;
}
else ringColor = (sidebarTab == 'collapse' && collapsed || (activeTab == sidebarTab)) ? ringOnColor : ringOffColor;
const name = settings.displaySidebarName ? this.getSidebarName(sidebarTab) : '';
const icon = settings.displaySidebarIcon ? this.getSidebarIcon(sidebarTab) : '';
@@ -495,26 +506,63 @@ export class OtherControls{
keyPressSidebar(settings){
if (MODULE.getPermission('OTHER','SIDEBAR') == false ) return;
const sidebarTab = settings.sidebarTab ? settings.sidebarTab : 'chat';
const popOut = settings.sidebarPopOut ? settings.sidebarPopOut : false;
if (sidebarTab == 'collapse'){
const collapsed = ui.sidebar._collapsed;
if (collapsed) ui.sidebar.expand();
else if (collapsed == false) ui.sidebar.collapse();
}
else ui.sidebar.activateTab(sidebarTab);
else if (popOut == false) ui.sidebar.activateTab(sidebarTab);
else {
const element = document.getElementById(sidebarTab+"-popout");
if (element == null) ui?.[sidebarTab].renderPopout();
else element.getElementsByClassName("close")[0].click();
}
}
//////////////////////////////////////////////////////////////////////////////////////////
updateCompendium(settings,context){
updateCompendiumBrowser(settings,context,options={}){
let rendered = options.renderCompendiumBrowser;
if (rendered == undefined && game.system.id == "pf2e") rendered = (document.getElementById("app-1") != null);
else if (rendered == undefined) rendered = (document.getElementById("compendium-popout") != null);
const background = settings.background ? settings.background : '#000000';
const ringOffColor = settings.offRing ? settings.offRing : '#000000';
const ringOnColor = settings.onRing ? settings.onRing : '#00FF00';
const ringColor = rendered ? ringOnColor : ringOffColor;
const txt = settings.displayCompendiumName ? name : '';
streamDeck.setTitle(txt,context);
streamDeck.setIcon(context,"",{background:background,ring:2,ringColor:ringColor});
}
keyPressCompendiumBrowser(settings){
let element = null;
if (game.system.id == "pf2e") element = document.getElementById("app-1")
else element = document.getElementById("compendium-popout");
const rendered = (element != null);
if (rendered)
element.getElementsByClassName("close")[0].click();
else if (game.system.id == "pf2e")
document.getElementsByClassName("compendium-browser-btn")[0].click()
else
ui.compendium.renderPopout();
}
//////////////////////////////////////////////////////////////////////////////////////////
updateCompendium(settings,context,options={}){
const name = settings.compendiumName;
if (name == undefined) return;
if (MODULE.getPermission('OTHER','COMPENDIUM') == false ) {
streamDeck.noPermission(context);
return;
}
const compendium = game.packs.entries.find(p=>p.metadata.label == name);
let compendium;
if (compatibleCore("0.8.1")) compendium = game.packs.contents.find(p=>p.metadata.label == name)?.apps[0];
else compendium = game.packs.entries.find(p=>p.metadata.label == name);
if (compendium == undefined) return;
if (compendium.private && MODULE.getPermission('OTHER','COMPENDIUM_ALL') == false) {
streamDeck.noPermission(context);
@@ -535,16 +583,18 @@ export class OtherControls{
if (name == undefined) return;
if (MODULE.getPermission('OTHER','COMPENDIUM') == false ) return;
const compendium = game.packs.entries.find(p=>p.metadata.label == name);
let compendium;
if (compatibleCore("0.8.1")) compendium = game.packs.contents.find(p=>p.metadata.label == name)?.apps[0];
else compendium = game.packs.entries.find(p=>p.metadata.label == name);
if (compendium == undefined) return;
if (compendium.private && MODULE.getPermission('OTHER','COMPENDIUM_ALL') == false) return;
if (compendium.rendered) compendium.close();
else if (compendium.rendered) compendium.close();
else compendium.render(true);
}
//////////////////////////////////////////////////////////////////////////////////////////
updateJournal(settings,context){
updateJournal(settings,context,options={}){
const name = settings.compendiumName;
if (name == undefined) return;
@@ -559,11 +609,19 @@ export class OtherControls{
streamDeck.noPermission(context);
return;
}
let rendered = false;
if (options?.sheet?.title == name) {
if (options.hook == 'renderJournalSheet') rendered = true;
else if (options.hook == 'closeJournalSheet') rendered = false;
}
else
if (document.getElementById("journalentry-sheet-"+journal.id) != null) rendered = true;
const background = settings.background ? settings.background : '#000000';
const ringOffColor = settings.offRing ? settings.offRing : '#000000';
const ringOnColor = settings.onRing ? settings.onRing : '#00FF00';
const ringColor = journal.sheet.rendered ? ringOnColor : ringOffColor;
const ringColor = rendered ? ringOnColor : ringOffColor;
const txt = settings.displayCompendiumName ? name : '';
streamDeck.setTitle(txt,context);
@@ -580,14 +638,13 @@ export class OtherControls{
if (MODULE.getPermission('OTHER','JOURNAL') == false ) return;
if (journal.permission < 2 && MODULE.getPermission('OTHER','JOURNAL_ALL') == false ) return;
const element = document.getElementById("journal-"+journal.id);
if (element == null) journal.render(true);
if (journal.sheet.rendered == false) journal.sheet.render(true);
else journal.sheet.close();
}
//////////////////////////////////////////////////////////////////////////////////////////
updateChatMessage(settings,context){
updateChatMessage(settings,context,options={}){
if (MODULE.getPermission('OTHER','CHAT') == false ) {
streamDeck.noPermission(context);
return;

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class PlaylistControl{
constructor(){
@@ -106,10 +107,13 @@ export class PlaylistControl{
if (isNaN(trackNr) || trackNr < 1) trackNr = 1;
trackNr--;
trackNr += this.trackOffset;
let playlist = this.getPlaylist(playlistNr);
if (playlist != undefined){
let track = playlist.data.sounds[trackNr];
let track;
if (compatibleCore("0.8.1")) track = playlist.sounds.contents[trackNr];
else track = playlist.data.sounds[trackNr];
if (track != undefined){
if (track.playing)
ringColor = ringOnColor;
@@ -191,7 +195,9 @@ export class PlaylistControl{
if (playlistMode == 'playlist')
this.playPlaylist(playlist,playlistNr);
else {
let track = playlist.data.sounds[trackNr];
let track;
if (compatibleCore("0.8.1")) track = playlist.sounds.contents[trackNr];
else track = playlist.data.sounds[trackNr];
if (track != undefined){
this.playTrack(track,playlist,playlistNr);
}
@@ -276,7 +282,11 @@ export class PlaylistControl{
}
else if (mode == 2) await playlist.stopAll();
}
await playlist.updateEmbeddedEntity("PlaylistSound", {_id: track._id, playing: play});
if (compatibleCore("0.8.1") && play) await playlist.playSound(track);
else if (compatibleCore("0.8.1")) await playlist.stopSound(track);
else await playlist.updateEmbeddedEntity("PlaylistSound", {_id: track._id, playing: play});
playlist.update({playing: play});
}
}

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class SceneControl{
constructor(){
@@ -58,7 +59,7 @@ export class SceneControl{
let sceneList = [];
for (let i=0; i<ui.scenes.tree.children.length; i++){
const scenesInFolder = ui.scenes.tree.children[i].entities;
const scenesInFolder = compatibleCore("0.8.1") ? ui.scenes.tree.children[i].contents : ui.scenes.tree.children[i].entities;
for (let j=0; j<scenesInFolder.length; j++)
sceneList.push(scenesInFolder[j])
}
@@ -151,7 +152,7 @@ export class SceneControl{
let sceneList = [];
for (let i=0; i<ui.scenes.tree.children.length; i++){
const scenesInFolder = ui.scenes.tree.children[i].entities;
const scenesInFolder = compatibleCore("0.8.1") ? ui.scenes.tree.children[i].contents : ui.scenes.tree.children[i].entities;
for (let j=0; j<scenesInFolder.length; j++)
sceneList.push(scenesInFolder[j])
}

View File

@@ -18,6 +18,7 @@ const defaultUserPermissions = {
},
MACRO: {
HOTBAR: [true,true,true,true],
BY_NAME: [false,false,true,true],
MACROBOARD: [false,false,true,true],
MACROBOARD_CONFIGURE: [false,false,true,true]
},
@@ -208,6 +209,7 @@ export const registerSettings = async function() {
else {
if (permissionSettings.permissions.TOKEN.NON_OWNED == undefined) permissionSettings.permissions.TOKEN.NON_OWNED = [false,false,true,true];
if (permissionSettings.permissions.TOKEN.OBSERVER == undefined) permissionSettings.permissions.TOKEN.OBSERVER = [false,true,true,true];
if (permissionSettings.permissions.MACRO.BY_NAME == undefined) permissionSettings.permissions.MACRO.BY_NAME = [false,false,true,true];
}
game.settings.set(MODULE.moduleName,'userPermission',permissionSettings);

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class SoundboardControl{
constructor(){
@@ -87,7 +88,7 @@ export class SoundboardControl{
const repeat = (playMode > 0) ? true : false;
const play = (this.activeSounds[soundNr] == false) ? true : false;
this.playSound(soundNr,repeat,play);
this.prePlaySound(soundNr,repeat,play);
}
else if (mode == 'offset') { //Offset
let offset = parseInt(settings.offset);
@@ -98,7 +99,7 @@ export class SoundboardControl{
else if (mode == 'stopAll') { //Stop All Sounds
for (let i=0; i<64; i++) {
if (this.activeSounds[i] != false){
this.playSound(i,false,false);
this.prePlaySound(i,false,false);
}
}
}
@@ -118,10 +119,10 @@ export class SoundboardControl{
const playMode = game.settings.get(MODULE.moduleName,'soundboardSettings').mode[soundNr];
if (playMode == 2)
this.playSound(soundNr,false,false);
this.prePlaySound(soundNr,false,false);
}
async playSound(soundNr,repeat,play){
async prePlaySound(soundNr,repeat,play){
const soundBoardSettings = game.settings.get(MODULE.moduleName,'soundboardSettings');
const playlistId = (soundBoardSettings.selectedPlaylists != undefined) ? soundBoardSettings.selectedPlaylists[soundNr] : undefined;
let src;
@@ -142,7 +143,7 @@ export class SoundboardControl{
const soundId = soundBoardSettings.sounds[soundNr];
const sounds = game.playlists.get(playlistId).sounds;
if (sounds == undefined) return;
const sound = sounds.find(p => p._id == soundId);
const sound = compatibleCore("0.8.1") ? sounds.find(p => p.id == soundId) : sounds.find(p => p._id == soundId);
if (sound == undefined) return;
src = sound.path;
}
@@ -160,21 +161,39 @@ export class SoundboardControl{
};
game.socket.emit(`module.MaterialDeck`, payload);
if (play){
volume *= game.settings.get("core", "globalInterfaceVolume");
this.playSound(soundNr,src,play,repeat,volume)
}
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
if (repeat == false){
async playSound(soundNr,src,play,repeat,volume){
if (play){
volume *= game.settings.get("core", "globalAmbientVolume");
if (compatibleCore("0.8.1")) {
let newSound = new SoundNode(src);
if(newSound.loaded == false) await newSound.load({autoplay:true});
newSound.on('end', ()=>{
if (repeat == false) {
this.activeSounds[soundNr] = false;
this.updateAll();
}
});
newSound.play({loop:repeat,volume:volume});
this.activeSounds[soundNr] = newSound;
}
else {
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
if (repeat == false){
this.activeSounds[soundNr] = false;
this.updateAll();
}
},
onstop: ()=>{
this.activeSounds[soundNr] = false;
this.updateAll();
}
},
onstop: (id)=>{
this.activeSounds[soundNr] = false;
this.updateAll();
}});
howl.play();
this.activeSounds[soundNr] = howl;
}});
howl.play();
this.activeSounds[soundNr] = howl;
}
}
else {
this.activeSounds[soundNr].stop();
@@ -182,4 +201,23 @@ export class SoundboardControl{
}
this.updateAll();
}
/*
volumeChange(soundNr){
let volume = game.settings.get("core", "globalAmbientVolume");
if (soundNr == 'all') {
for (let i=0; this.activeSounds.length; i++) {
volume * game.settings.get(MODULE.moduleName,'soundboardSettings').volume[i]/100;
volume = AudioHelper.inputToVolume(volume);
this.activeSounds[i].volume = volume;
}
}
else {
volume * game.settings.get(MODULE.moduleName,'soundboardSettings').volume[soundNr]/100;
volume = AudioHelper.inputToVolume(volume);
}
}
*/
}

View File

@@ -354,6 +354,11 @@ export class StreamDeck{
}
else {
}
if (uses != undefined && uses.heart && (uses.available > 0 || uses.maximum != undefined)) {
const percentage = 102*uses.available/uses.maximum;
ctx.fillStyle = "#FF0000";
ctx.fillRect(0, 121,144,-percentage);
}
if (format == 'icon' && url != ""){
ctx.font = '600 90px "Font Awesome 5 Free"';
@@ -411,7 +416,7 @@ export class StreamDeck{
yStart = 0;
}
ctx.drawImage(img, xStart+margin, yStart+margin, renderableWidth - 2*margin, renderableHeight - 2*margin);
if (uses != undefined && (uses.available > 0 || uses.maximum != undefined)) {
if (uses != undefined && uses.heart == false && (uses.available > 0 || uses.maximum != undefined)) {
let txt = uses.available;
if (uses.maximum != undefined) txt = uses.available + '/' + uses.maximum;
if (uses.maximum == undefined ) uses.maximum = 1;
@@ -526,7 +531,8 @@ export class StreamDeck{
this.imageBuffer = [];
}
noPermission(context,showTxt=true){
noPermission(context,showTxt=true, origin = ""){
console.warn("Material Deck: User lacks permission for function "+origin);
const url = 'modules/MaterialDeck/img/black.png';
const background = '#000000';
const txt = showTxt ? 'no\npermission' : '';

View File

@@ -1,5 +1,6 @@
import * as MODULE from "../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {streamDeck, macroControl} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class TokenControl{
constructor(){
@@ -41,6 +42,7 @@ export class TokenControl{
let overlay = false;
let statsOld;
let uses = undefined;
let hp = undefined;
if (validToken) {
if (token.owner == false && token.observer == true && MODULE.getPermission('TOKEN','OBSERVER') == false ) {
streamDeck.noPermission(context);
@@ -93,12 +95,18 @@ export class TokenControl{
else if (game.system.id == 'dnd5e'){
let attributes = token.actor.data.data.attributes;
if (stats == 'HP') {
uses = {
available: attributes.hp.value,
maximum: attributes.hp.max,
heart: true
};
txt += attributes.hp.value + "/" + attributes.hp.max;
}
else if (stats == 'HPbox') {
uses = {
available: attributes.hp.value,
maximum: attributes.hp.max
maximum: attributes.hp.max,
heart: false
}
}
else if (stats == 'TempHP') {
@@ -138,7 +146,11 @@ export class TokenControl{
}
txt += speed;
}
else if (stats == 'Init') txt += attributes.init.total;
else if (stats == 'Init') {
const value = attributes.init.total;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'PassivePerception') txt += token.actor.data.data.skills.prc.passive;
else if (stats == 'PassiveInvestigation') txt += token.actor.data.data.skills.inv.passive;
else if (stats == 'Ability') {
@@ -147,11 +159,21 @@ export class TokenControl{
}
else if (stats == 'AbilityMod') {
const ability = settings.ability ? settings.ability : 'str';
txt += token.actor.data.data.abilities?.[ability].mod;
const value = token.actor.data.data.abilities?.[ability].mod;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'AbilitySave') {
const ability = settings.ability ? settings.ability : 'str';
txt += token.actor.data.data.abilities?.[ability].save;
else if (stats == 'Save') {
const ability = settings.save ? settings.save : 'str';
const value = token.actor.data.data.abilities?.[ability].save;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'Skill') {
const skill = settings.skill ? settings.skill : 'acr';
const value = token.actor.data.data.skills?.[skill].mod;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'Prof') txt += token.actor.data.data.attributes.prof;
}
@@ -191,18 +213,32 @@ export class TokenControl{
}
txt += speed;
}
else if (stats == 'Init') txt += attributes.init.total;
else if (stats == 'Init') {
const value = attributes.init.total;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'Ability') {
const ability = settings.ability ? settings.ability : 'str';
txt += token.actor.data.data.abilities?.[ability].value;
}
else if (stats == 'AbilityMod') {
const ability = settings.ability ? settings.ability : 'str';
txt += token.actor.data.data.abilities?.[ability].mod;
const value = token.actor.data.data.abilities?.[ability].mod;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'AbilitySave') {
const ability = settings.ability ? settings.ability : 'str';
txt += token.actor.data.data.abilities?.[ability].save;
else if (stats == 'Save') {
const ability = settings.save ? settings.save : 'fort';
const value = token.actor.data.data.attributes.savingThrows?.[ability].total;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'Skill') {
const skill = settings.skill ? settings.skill : 'apr';
const value = token.actor.data.data.skills?.[skill].mod;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'Prof') txt += token.actor.data.data.attributes.prof;
}
@@ -224,7 +260,7 @@ export class TokenControl{
}
else if (stats == 'AC') txt += attributes.ac.value;
else if (stats == 'Speed'){
let speed = "Land: " + attributes.speed.value.replace('feet','') + ' feet';
let speed = attributes.speed.breakdown;
const otherSpeeds = attributes.speed.otherSpeeds;
if (otherSpeeds.length > 0)
for (let i=0; i<otherSpeeds.length; i++)
@@ -232,8 +268,36 @@ export class TokenControl{
txt += speed;
}
else if (stats == 'Init') {
let init = attributes.initiative.totalModifier;
if (init != undefined) txt += init;
const value = attributes.init.value;
if (value != undefined) {
if (value >= 0) txt += "+";
txt += value;
}
}
else if (stats == 'Ability') {
const ability = settings.ability ? settings.ability : 'str';
txt += token.actor.data.data.abilities?.[ability].value;
}
else if (stats == 'AbilityMod') {
const ability = settings.ability ? settings.ability : 'str';
const value = token.actor.data.data.abilities?.[ability].mod;
if (value >= 0) txt += '+';
txt += value;
}
else if (stats == 'Save') {
let ability = settings.save ? settings.save : 'fort';
if (ability == 'fort') ability = 'fortitude';
else if (ability == 'ref') ability = 'reflex';
else if (ability == 'will') ability = 'will';
const value = token.actor.data.data.saves?.[ability].value;
if (value >= 0) txt += "+";
txt += value;
}
else if (stats == 'Skill') {
const skill = settings.skill ? settings.skill : 'acr';
const value = token.actor.data.data.skills?.[skill].totalModifier;
if (value >= 0) txt += '+';
txt += value;
}
}
else if (game.system.id == 'demonlord'){
@@ -250,11 +314,15 @@ export class TokenControl{
else if (stats == 'Init') txt += token.actor.data.data.fastturn ? "FAST" : "SLOW";
else if (stats == 'Ability') {
const ability = settings.ability ? settings.ability : 'strength';
txt += token.actor.data.data.attributes?.[ability].value;
const value = token.actor.data.data.attributes?.[ability].value;
if (value >=0) txt += '+';
txt += value;
}
else if (stats == 'AbilityMod') {
const ability = settings.ability ? settings.ability : 'strength';
txt += token.actor.data.data.attributes?.[ability].modifier;
const value = token.actor.data.data.attributes?.[ability].modifier;
if (value >=0) txt += '+';
txt += value;
}
}
else {
@@ -318,7 +386,7 @@ export class TokenControl{
else if (icon == false) {
let effect = CONFIG.statusEffects.find(e => e.id === condition);
iconSrc = effect.icon;
let effects = token.actor.effects.entries;
let effects = compatibleCore("0.8.1") ? token.actor.effects.contents : token.actor.effects.entries;
let active = effects.find(e => e.isTemporary === condition);
if (active != undefined){
ring = 2;
@@ -372,7 +440,7 @@ export class TokenControl{
if (icon == false) {
let effect = CONFIG.statusEffects.find(e => e.label === condition);
iconSrc = effect.icon;
let effects = token.actor.effects.entries;
let effects = compatibleCore("0.8.1") ? token.actor.effects.contents : token.actor.effects.entries;
let active = effects.find(e => e.isTemporary === effect.id);
if (active != undefined){
ring = 2;
@@ -495,7 +563,7 @@ export class TokenControl{
if (icon == false){
if (MODULE.getPermission('TOKEN','STATS') == false) stats = statsOld;
if (stats == 'HP' || stats == 'TempHP') //HP
iconSrc = "modules/MaterialDeck/img/token/hp.png";
iconSrc = "modules/MaterialDeck/img/token/hp_empty.png";
else if (stats == 'AC' || stats == 'ShieldHP') //AC
iconSrc = "modules/MaterialDeck/img/token/ac.webp";
else if (stats == 'Speed') //Speed
@@ -507,7 +575,7 @@ export class TokenControl{
else if (stats == 'PassiveInvestigation')
iconSrc = "modules/MaterialDeck/img/black.png";
}
streamDeck.setIcon(context,iconSrc,{background:background,ring:ring,ringColor:ringColor,overlay:overlay,uses:uses});
streamDeck.setIcon(context,iconSrc,{background:background,ring:ring,ringColor:ringColor,overlay:overlay,uses:uses,hp:hp});
streamDeck.setTitle(txt,context);
}
@@ -606,7 +674,7 @@ export class TokenControl{
this.update(tokenId);
}
else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions
else if (onClick == 'cubCondition') { //Combat Utility Belt conditions
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) return;
const condition = settings.cubConditionName;
if (condition == undefined || condition == '') return;
@@ -696,6 +764,48 @@ export class TokenControl{
iconSrc = images[imgNr];
token.update({img: iconSrc})
}
else if (onClick == 'macro') { //call a macro
const settingsNew = {
target: token,
macroMode: settings.macroMode,
macroNumber: settings.macroId,
macroArgs: settings.macroArgs
}
macroControl.keyPress(settingsNew);
}
else if (onClick == 'roll') { //roll skill/save/ability
const roll = settings.roll ? settings.roll : 'abilityCheck';
const ability = settings.rollAbility ? settings.rollAbility : 'str';
const skill = settings.rollSkill ? settings.rollSkill : 'acr';
const save = settings.rollSave ? settings.rollSave : 'str';
if (game.system.id == 'pf2e') {
if (roll == 'abilityCheck') token.actor.data.data.saves?.[ability].roll();
else if (roll == 'save') {
let ability = save;
if (ability == 'fort') ability = 'fortitude';
else if (ability == 'ref') ability = 'reflex';
else if (ability == 'will') ability = 'will';
token.actor.data.data.saves?.[ability].roll();
}
else if (roll == 'skill') token.actor.data.data.skills?.[skill].roll();
}
if (roll == 'abilityCheck') token.actor.rollAbilityTest(ability);
else if (roll == 'save') {
if (game.system.id == 'dnd5e') token.actor.rollAbilitySave(save);
else token.actor.rollSavingThrow(save);
}
else if (roll == 'skill') token.actor.rollSkill(skill);
else if (roll == 'initiative') token.actor.rollInitiative();
else if (roll == 'deathSave') token.actor.rollDeathSave();
else if (roll == 'grapple') token.actor.rollGrapple();
else if (roll == 'bab') token.actor.rollBAB();
else if (roll == 'melee') token.actor.rollMelee();
else if (roll == 'ranged') token.actor.rollRanged();
else if (roll == 'cmb') token.actor.rollCMB();
else if (roll == 'attack') token.actor.rollAttack();
else if (roll == 'defenses') token.actor.rollDefenses();
}
else if (onClick == 'custom') {//custom onClick function
if (MODULE.getPermission('TOKEN','CUSTOM') == false ) return;
const formula = settings.customOnClickFormula ? settings.customOnClickFormula : '';
@@ -705,19 +815,39 @@ export class TokenControl{
let formulaArrayTemp;
let split1 = formula.split(';');
for (let i=0; i<split1.length; i++){
let macro = false;
let furnaceArguments = "";
let split2 = split1[i].split(' = ');
targetArrayTemp = split2[0];
formulaArrayTemp = split2[1];
let targetArray = this.splitCustom(targetArrayTemp);
for (let i=0; i<targetArray.length; i++){
if (targetArray[i][0] == '@') {
const dataPath = targetArray[i].split('@')[1].split('.');
targetArray[i] = dataPath;
if (dataPath == 'macro') {
macro = true;
}
}
else if (macro) {
const data = targetArray[i].split('[');
if (data != undefined && data.length > 1) targetArray[i] = data[1];
if (i > 1) {
if (furnaceArguments != "") furnaceArguments += " ";
furnaceArguments += "\"" + targetArray[i] + "\"";
}
}
}
if (macro) {
const settingsNew = {
target: token,
macroMode: 'name',
macroNumber: targetArray[1],
macroArgs: furnaceArguments
}
macroControl.keyPress(settingsNew);
continue;
}
let formulaArray = this.splitCustom(formulaArrayTemp);
let value = 0;
@@ -774,7 +904,7 @@ export class TokenControl{
if (path != '') path += '.';
path += targetArray[i][j];
}
actor.update({[path]:value})
await actor.update({[path]:value})
}
else {
let path = '';
@@ -782,9 +912,9 @@ export class TokenControl{
if (path != '') path += '.';
path += targetArray[i][j];
}
actor.update({[path]:value})
await actor.update({[path]:value})
}
this.update(token.id);
}
else {
data = token;
@@ -793,8 +923,10 @@ export class TokenControl{
if (path != '') path += '.';
path += targetArray[i][j];
}
token.update({[path]:value})
await token.update({[path]:value})
this.update(token.id);
}
}
}
}